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
59 PROP_EVAS_OBJECT_SHOW,
60 #ifdef USE_NATIVE_BUFFER
62 PROP_DISPLAY_GEOMETRY_METHOD,
63 PROP_ENABLE_FLUSH_BUFFER,
75 #define GL_X11_ENGINE "gl_x11"
76 #define DO_RENDER_FROM_FIMC 1
77 #define SIZE_FOR_UPDATE_VISIBILITY sizeof(gchar)
78 #ifdef USE_NATIVE_BUFFER
79 #define MAX_ECOREPIPE_BUFFER_CNT 4
80 #define DEBUGLOG_DEFAULT_COUNT 8
81 #define SIZE_FOR_NATIVE_INDEX sizeof(gint)
83 /* max channel count *********************************************************/
84 #define SCMN_IMGB_MAX_PLANE (4)
86 /* image buffer definition ***************************************************
88 +------------------------------------------+ ---
91 | +---------------------------+ --- | |
93 | |<---------- w[] ---------->| | | |
101 | +---------------------------+ --- | |
103 +------------------------------------------+ ---
105 |<----------------- s[] ------------------>|
110 /* width of each image plane */
111 int w[SCMN_IMGB_MAX_PLANE];
112 /* height of each image plane */
113 int h[SCMN_IMGB_MAX_PLANE];
114 /* stride of each image plane */
115 int s[SCMN_IMGB_MAX_PLANE];
116 /* elevation of each image plane */
117 int e[SCMN_IMGB_MAX_PLANE];
118 /* user space address of each image plane */
119 void *a[SCMN_IMGB_MAX_PLANE];
120 /* physical address of each image plane, if needs */
121 void *p[SCMN_IMGB_MAX_PLANE];
122 /* color space type of image */
124 /* left postion, if needs */
126 /* top position, if needs */
128 /* to align memory */
133 int fd[SCMN_IMGB_MAX_PLANE];
134 /* buffer share method */
135 int buf_share_method;
136 /* Y plane size in case of ST12 */
138 /* UV plane size in case of ST12 */
140 /* Tizen buffer object */
141 void *bo[SCMN_IMGB_MAX_PLANE];
146 /* TZ memory buffer */
151 #define EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object, x_usr_data ) \
154 if (x_evas_image_object) { \
155 GST_LOG("object callback add"); \
156 evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event, x_usr_data); \
157 evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, x_usr_data); \
161 #define EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object ) \
164 if (x_evas_image_object) { \
165 GST_LOG("object callback del"); \
166 evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event); \
167 evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); \
171 #ifdef USE_NATIVE_BUFFER
172 #define EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK( x_evas, x_usr_data ) \
176 GST_DEBUG("callback add... evas_callback_render_pre.. evas : %p esink : %p", x_evas, x_usr_data); \
177 evas_event_callback_add (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre, x_usr_data); \
181 #define EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK( x_evas ) \
185 GST_DEBUG("callback del... evas_callback_render_pre"); \
186 evas_event_callback_del (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre); \
191 GMutex *instance_lock;
192 guint instance_lock_count;
194 static inline gboolean
195 is_evas_image_object (Evas_Object *obj)
201 type = evas_object_type_get (obj);
205 if (strcmp (type, "image") == 0) {
211 #ifdef USE_NATIVE_BUFFER
213 gst_evas_image_sink_ref_count (GstBuffer * buf)
215 return GST_OBJECT_REFCOUNT_VALUE(GST_BUFFER_CAST(buf));
219 /* the capabilities of the inputs.
223 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
227 GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx));
229 #ifdef USE_NATIVE_BUFFER
230 GST_STATIC_CAPS(GST_VIDEO_CAPS_YUV ("I420") ";"
231 GST_VIDEO_CAPS_YUV ("NV12") ";"
232 GST_VIDEO_CAPS_YUV ("SN12"))
235 GST_BOILERPLATE (GstEvasImageSink, gst_evas_image_sink, GstVideoSink, GST_TYPE_VIDEO_SINK);
237 static void gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
238 static void gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
239 static gboolean gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps);
240 static GstFlowReturn gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf);
241 static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event);
242 static GstStateChangeReturn gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition);
243 static void evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info);
244 static void evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info);
245 #ifdef USE_NATIVE_BUFFER
246 static void evas_callback_render_pre (void *data, Evas *e, void *event_info);
247 static GstFlowReturn gst_esink_epipe_reset(GstEvasImageSink *esink);
248 static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink);
249 static void _release_flush_buffer(GstEvasImageSink *esink);
250 static void gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result);
251 static void gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink);
254 gst_evas_image_sink_base_init (gpointer gclass)
256 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
258 gst_element_class_set_details_simple (element_class,
261 "Video sink element for evas image object",
262 "Samsung Electronics <www.samsung.com>");
264 gst_element_class_add_pad_template (element_class,
265 gst_static_pad_template_get (&sink_factory));
269 gst_evas_image_sink_class_init (GstEvasImageSinkClass *klass)
271 GObjectClass *gobject_class;
272 GstBaseSinkClass *gstbasesink_class;
273 GstVideoSinkClass *gstvideosink_class;
274 GstElementClass *gstelement_class;
276 gobject_class = (GObjectClass *) klass;
277 gstbasesink_class = GST_BASE_SINK_CLASS (klass);
278 gstvideosink_class = GST_VIDEO_SINK_CLASS (klass);
279 gstelement_class = (GstElementClass *) klass;
281 gobject_class->set_property = gst_evas_image_sink_set_property;
282 gobject_class->get_property = gst_evas_image_sink_get_property;
284 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
285 g_param_spec_pointer ("evas-object", "Destination Evas Object", "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT_SHOW,
287 g_param_spec_boolean ("visible", "Show Evas Object", "When disabled, evas object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
288 #ifdef USE_NATIVE_BUFFER
289 g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE,
290 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));
291 g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
292 g_param_spec_int("display-geometry-method", "Display geometry method",
293 "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));
294 g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
295 g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
296 "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
297 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
298 g_object_class_install_property(gobject_class, PROP_FLIP,
299 g_param_spec_int("flip", "Display flip",
300 "Flip for display", FLIP_NONE, FLIP_NUM, FLIP_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302 gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evas_image_sink_show_frame);
303 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evas_image_sink_set_caps);
304 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evas_image_sink_event);
305 gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_evas_image_sink_change_state);
309 gst_evas_image_sink_fini (gpointer data, GObject *obj)
311 GST_DEBUG ("[ENTER]");
313 GstEvasImageSink *esink = GST_EVASIMAGESINK (obj);
319 gst_buffer_unref (esink->oldbuf);
324 #ifdef USE_NATIVE_BUFFER
325 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
326 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
328 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
329 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
330 evas_object_image_data_set(esink->eo, NULL);
332 #ifdef USE_NATIVE_BUFFER
333 if (esink->display_buffer_lock) {
334 g_mutex_free (esink->display_buffer_lock);
335 esink->display_buffer_lock = NULL;
337 if (esink->flow_lock) {
338 g_mutex_free (esink->flow_lock);
339 esink->flow_lock = NULL;
341 if(esink->n_provider)
342 native_buffer_provider_destroy(esink->n_provider);
346 g_mutex_lock (instance_lock);
347 instance_lock_count--;
348 g_mutex_unlock (instance_lock);
349 if (instance_lock_count == 0) {
350 g_mutex_free (instance_lock);
351 instance_lock = NULL;
354 GST_DEBUG ("[LEAVE]");
357 #ifdef USE_NATIVE_BUFFER
359 gst_evas_image_sink_reset (GstEvasImageSink *esink)
362 tbm_bo_handle bo_handle;
364 GST_DEBUG("gst_evas_image_sink_reset start");
366 g_mutex_lock(esink->display_buffer_lock);
368 for(i=0; i<NATIVE_BUFFER_NUM; i++)
370 if(esink->displaying_buffer[i].n_buffer)
372 native_buffer_destroy(esink->displaying_buffer[i].n_buffer);
373 esink->displaying_buffer[i].n_buffer = NULL;
375 if(esink->displaying_buffer[i].buffer)
377 if(esink->displaying_buffer[i].ref_count)
379 if(esink->displaying_buffer[i].bo) {
380 bo_handle = tbm_bo_map(esink->displaying_buffer[i].bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
381 if (!bo_handle.ptr) {
382 GST_WARNING("failed to map bo [%p]", esink->displaying_buffer[i].bo);
385 tbm_bo_unmap(esink->displaying_buffer[i].bo);
388 GST_WARNING("there is no bo information. so skip to map bo");
390 GST_WARNING("[reset] unreffing gst %p", esink->displaying_buffer[i].buffer);
392 while(esink->displaying_buffer[i].ref_count)
394 GST_WARNING("index[%d]'s buffer ref count=%d",i,gst_evas_image_sink_ref_count (esink->displaying_buffer[i].buffer));
395 esink->displaying_buffer[i].ref_count--;
396 gst_buffer_unref(esink->displaying_buffer[i].buffer);
399 esink->displaying_buffer[i].buffer = NULL;
401 if(esink->displaying_buffer[i].bo)
402 esink->displaying_buffer[i].bo = NULL;
404 esink->prev_buf = NULL;
405 esink->prev_index = -1;
406 esink->cur_index = -1;
408 esink->eo_size.x = esink->eo_size.y =
409 esink->eo_size.w = esink->eo_size.h = 0;
410 esink->use_ratio = FALSE;
411 esink->sent_buffer_cnt = 0;
413 g_mutex_unlock(esink->display_buffer_lock);
419 evas_image_sink_cb_pipe (void *data, void *buffer, unsigned int nbyte)
421 #ifdef USE_NATIVE_BUFFER
423 evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte)
426 GstEvasImageSink *esink = data;
431 GST_DEBUG ("[ENTER]");
432 if (!esink || !esink->eo) {
433 GST_WARNING ("esink : %p, or eo is NULL returning", esink);
436 GST_LOG("esink : %p, esink->eo : %x", esink, esink->eo);
437 if (nbyte == SIZE_FOR_UPDATE_VISIBILITY) {
438 if(!esink->object_show) {
439 evas_object_hide(esink->eo);
440 GST_INFO ("object hide..");
442 evas_object_show(esink->eo);
443 GST_INFO ("object show..");
445 GST_DEBUG ("[LEAVE]");
449 if (!buffer || nbyte != sizeof (GstBuffer *)) {
450 GST_WARNING ("buffer %p, nbyte : %d, sizeof(GstBuffer *) : %d", buffer, nbyte, sizeof (GstBuffer *));
454 #ifdef USE_NATIVE_BUFFER
456 index = *buffer_index;
457 if ((index<0 || index>=NATIVE_BUFFER_NUM) || nbyte != SIZE_FOR_NATIVE_INDEX) {
458 GST_WARNING ("index : %d, nbyte : %d", index, nbyte);
462 if (GST_STATE(esink) < GST_STATE_PAUSED) {
463 GST_WARNING ("WRONG-STATE(%d) for rendering, skip this frame", GST_STATE(esink));
468 memcpy (&buf, buffer, sizeof (GstBuffer *));
470 GST_ERROR ("There is no buffer");
473 if (esink->present_data_addr == -1) {
474 /* if present_data_addr is -1, we don't use this member variable */
475 } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) {
476 GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC);
480 #ifdef USE_NATIVE_BUFFER
481 g_mutex_lock(esink->display_buffer_lock);
482 if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_NV12) {
483 if (!esink->displaying_buffer[index].n_buffer) {
484 GST_ERROR("the index's nbuffer was already NULL, so return");
485 g_mutex_unlock(esink->display_buffer_lock);
488 GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index);
489 } else if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_I420) {
490 GST_LOG("received (bo %p) index num : %d", esink->displaying_buffer[index].bo, index);
493 Evas_Native_Surface surf;
494 surf.type = EVAS_NATIVE_SURFACE_TIZEN;
495 surf.version = EVAS_NATIVE_SURFACE_VERSION;
496 surf.data.tizen.buffer = esink->displaying_buffer[index].n_buffer;
497 surf.data.tizen.rot = esink->rotate_angle;
498 surf.data.tizen.flip = esink->flip;
500 GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index);
502 GstVideoRectangle result = {0};
504 evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h);
505 if (!esink->eo_size.w || !esink->eo_size.h) {
506 GST_ERROR ("there is no information for evas object size");
507 g_mutex_unlock(esink->display_buffer_lock);
510 gst_evas_image_sink_update_geometry(esink, &result);
511 if(!result.w || !result.h)
513 GST_ERROR("no information about geometry (%d, %d)", result.w, result.h);
514 g_mutex_unlock(esink->display_buffer_lock);
520 surf.data.tizen.ratio = (float) esink->w / esink->h;
521 GST_LOG("set ratio for letter mode");
523 evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL);
524 evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
525 if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
526 evas_object_image_size_set(esink->eo, esink->w, esink->h);
527 esink->is_evas_object_size_set = TRUE;
529 evas_object_image_native_surface_set(esink->eo, &surf);
530 GST_DEBUG("native surface set finish");
532 if(result.x || result.y)
533 GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y);
534 evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h);
536 evas_object_image_pixels_dirty_set(esink->eo, EINA_TRUE);
537 GST_DEBUG_OBJECT (esink, "GEO_METHOD : src(%dx%d), dst(%dx%d), dst_x(%d), dst_y(%d), rotate(%d), flip(%d)",
538 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);
540 /* unref previous buffer */
541 if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_NV12) {
542 if(esink->prev_buf && esink->displaying_buffer[esink->prev_index].ref_count)
544 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);
545 esink->displaying_buffer[esink->prev_index].ref_count--;
546 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);
547 /* Print debug log for 8 frame */
548 if(esink->debuglog_cnt_ecoreCbPipe > 0)
550 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);
551 esink->debuglog_cnt_ecoreCbPipe--;
553 if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT)
554 GST_WARNING("sent buffer cnt 4->3 so skip will be stop");
556 esink->sent_buffer_cnt--;
557 GST_DEBUG("prev gst_buffer %p's unref Start!!", esink->prev_buf);
558 gst_buffer_unref(esink->prev_buf);
559 GST_DEBUG("prev gst_buffer %p's unref End!!", esink->prev_buf);
561 GST_DEBUG("ref_count=%d unref prev gst_buffer %p", esink->displaying_buffer[esink->prev_index].ref_count,esink->prev_buf);
564 GST_DEBUG("Current gst_buf %p and index=%d is overwrited to Prev gst_buf %p & index %d",
565 esink->displaying_buffer[index].buffer, index, esink->prev_buf, esink->prev_index );
566 esink->prev_buf = esink->displaying_buffer[index].buffer;
567 esink->prev_index = index;
568 }else if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_I420) {
569 /* Print debug log for 8 frame */
570 if(esink->debuglog_cnt_ecoreCbPipe > 0)
572 GST_WARNING("(%d) ecore_cb_pipe set native surface [%d] n_buffer[%p]",
573 DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_ecoreCbPipe), index, esink->displaying_buffer[index].n_buffer);
574 esink->debuglog_cnt_ecoreCbPipe--;
576 if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT)
577 GST_WARNING("sent buffer cnt 4->3 so skip will be stop");
579 esink->sent_buffer_cnt--;
583 if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
584 evas_object_image_size_set (esink->eo, esink->w, esink->h);
585 GST_DEBUG("evas_object_image_size_set(), width(%d),height(%d)", esink->w, esink->h);
586 esink->is_evas_object_size_set = TRUE;
588 if (esink->gl_zerocopy) {
589 img_data = evas_object_image_data_get (esink->eo, EINA_TRUE);
590 if (!img_data || !GST_BUFFER_DATA(buf)) {
591 GST_WARNING ("Cannot get image data from evas object or cannot get gstbuffer data");
592 evas_object_image_data_set(esink->eo, img_data);
594 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);
595 memcpy (img_data, GST_BUFFER_DATA (buf), esink->w * esink->h * COLOR_DEPTH);
596 evas_object_image_pixels_dirty_set (esink->eo, 1);
597 evas_object_image_data_set(esink->eo, img_data);
599 gst_buffer_unref (buf);
601 GST_DEBUG ("GST_BUFFER_DATA(buf):%x, esink->eo(%x)",GST_BUFFER_DATA(buf),esink->eo);
602 evas_object_image_data_set (esink->eo, GST_BUFFER_DATA (buf));
603 evas_object_image_pixels_dirty_set (esink->eo, 1);
605 gst_buffer_unref(esink->oldbuf);
610 #ifdef USE_NATIVE_BUFFER
611 g_mutex_unlock(esink->display_buffer_lock);
613 GST_DEBUG ("[LEAVE]");
615 #ifdef USE_NATIVE_BUFFER
617 gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result)
619 if (!esink || !esink->eo) {
620 GST_WARNING("there is no esink");
627 switch (esink->display_geometry_method)
629 case DISP_GEO_METHOD_LETTER_BOX: // 0
630 /* set black padding for letter box mode */
631 GST_DEBUG("letter box mode");
632 esink->use_ratio = TRUE;
633 result->w = esink->eo_size.w;
634 result->h = esink->eo_size.h;
636 case DISP_GEO_METHOD_ORIGIN_SIZE: // 1
637 GST_DEBUG("origin size mode");
638 esink->use_ratio = FALSE;
639 /* set coordinate for each case */
640 result->x = (esink->eo_size.w-esink->w) / 2;
641 result->y = (esink->eo_size.h-esink->h) / 2;
642 result->w = esink->w;
643 result->h = esink->h;
645 case DISP_GEO_METHOD_FULL_SCREEN: // 2
646 GST_DEBUG("full screen mode");
647 esink->use_ratio = FALSE;
648 result->w = esink->eo_size.w;
649 result->h = esink->eo_size.h;
651 case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: // 3
652 GST_DEBUG("cropped full screen mode");
653 esink->use_ratio = FALSE;
654 /* compare evas object's ratio with video's */
655 if((esink->eo_size.w/esink->eo_size.h) > (esink->w/esink->h))
657 result->w = esink->eo_size.w;
658 result->h = esink->eo_size.w * esink->h / esink->w;
659 result->y = -(result->h-esink->eo_size.h) / 2;
663 result->w = esink->eo_size.h * esink->w / esink->h;
664 result->h = esink->eo_size.h;
665 result->x = -(result->w-esink->eo_size.w) / 2;
668 case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX: // 4
669 GST_DEBUG("origin size or letter box mode");
670 /* if video size is smaller than evas object's, it will be set to origin size mode */
671 if((esink->eo_size.w > esink->w) && (esink->eo_size.h > esink->h))
673 GST_DEBUG("origin size mode");
674 esink->use_ratio = FALSE;
675 /* set coordinate for each case */
676 result->x = (esink->eo_size.w-esink->w) / 2;
677 result->y = (esink->eo_size.h-esink->h) / 2;
678 result->w = esink->w;
679 result->h = esink->h;
683 GST_DEBUG("letter box mode");
684 esink->use_ratio = TRUE;
685 result->w = esink->eo_size.w;
686 result->h = esink->eo_size.h;
690 GST_WARNING("unsupported mode.");
693 GST_DEBUG("geometry result [%d, %d, %d, %d]", result->x, result->y, result->w, result->h);
696 gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink)
698 if (!esink || !esink->eo) {
699 GST_WARNING("there is no esink");
703 Evas_Native_Surface *surf = evas_object_image_native_surface_get(esink->eo);
704 GstVideoRectangle result = {0};
708 GST_DEBUG("native surface exists");
709 surf->data.tizen.rot = esink->rotate_angle;
710 surf->data.tizen.flip = esink->flip;
711 evas_object_image_native_surface_set(esink->eo, surf);
713 gst_evas_image_sink_update_geometry(esink, &result);
717 surf->data.tizen.ratio = (float) esink->w / esink->h;
718 GST_LOG("set ratio for letter mode");
721 if(result.x || result.y)
722 GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y);
724 evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h);
727 GST_WARNING("there is no surf");
732 gst_evas_image_sink_init (GstEvasImageSink *esink, GstEvasImageSinkClass *gclass)
734 GST_DEBUG ("[ENTER]");
738 esink->object_show = FALSE;
739 esink->update_visibility = UPDATE_FALSE;
740 esink->is_evas_object_size_set = FALSE;
742 esink->gl_zerocopy = FALSE;
743 esink->present_data_addr = -1;
745 #ifdef USE_NATIVE_BUFFER
746 esink->display_buffer_lock = g_mutex_new ();
747 esink->flow_lock = g_mutex_new ();
748 esink->n_provider = native_buffer_provider_create (NATIVE_BUFFER_PROVIDER_CORE);
750 for (i=0; i<NATIVE_BUFFER_NUM; i++)
752 esink->displaying_buffer[i].n_buffer = NULL;
753 esink->displaying_buffer[i].buffer = NULL;
754 esink->displaying_buffer[i].bo = NULL;
755 esink->displaying_buffer[i].ref_count = 0;
757 esink->prev_buf = NULL;
758 esink->prev_index = -1;
759 esink->cur_index = -1;
760 esink->enable_flush_buffer = TRUE;
761 esink->need_flush = FALSE;
762 esink->display_geometry_method = DISP_GEO_METHOD_LETTER_BOX;
763 esink->flip = FLIP_NONE;
764 esink->eo_size.x = esink->eo_size.y =
765 esink->eo_size.w = esink->eo_size.h = 0;
766 esink->use_ratio = FALSE;
767 esink->sent_buffer_cnt = 0;
768 esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT;
769 esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT;
771 esink->src_buf_idx = 0;
772 esink->is_buffer_allocated = FALSE;
775 instance_lock = g_mutex_new();
777 g_mutex_lock (instance_lock);
778 instance_lock_count++;
779 g_mutex_unlock (instance_lock);
781 g_object_weak_ref (G_OBJECT (esink), gst_evas_image_sink_fini, NULL);
783 GST_DEBUG ("[LEAVE]");
787 evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
789 GST_DEBUG ("[ENTER]");
791 GstEvasImageSink *esink = data;
798 gst_buffer_unref (esink->oldbuf);
799 esink->oldbuf = NULL;
803 #ifdef USE_NATIVE_BUFFER
804 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
805 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
807 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
808 GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo);
810 evas_object_image_data_set(esink->eo, NULL);
814 GST_DEBUG ("[LEAVE]");
818 evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info)
823 GST_DEBUG ("[ENTER]");
825 GstEvasImageSink *esink = data;
826 if (!esink || !esink->eo) {
830 evas_object_geometry_get(esink->eo, &x, &y, &w, &h);
832 GST_WARNING ("evas object size (w:%d,h:%d) was not set", w, h);
834 #ifdef USE_NATIVE_BUFFER
835 esink->eo_size.x = x;
836 esink->eo_size.y = y;
837 esink->eo_size.w = w;
838 esink->eo_size.h = h;
839 GST_WARNING ("resize (x:%d, y:%d, w:%d, h:%d)", x, y, w, h);
840 gst_evas_image_sink_apply_geometry(esink);
843 evas_object_image_fill_set(esink->eo, 0, 0, w, h);
844 GST_DEBUG ("evas object fill set (w:%d,h:%d)", w, h);
848 GST_DEBUG ("[LEAVE]");
850 #ifdef USE_NATIVE_BUFFER
852 evas_callback_render_pre (void *data, Evas *e, void *event_info)
854 GstEvasImageSink *esink = data;
855 if (!esink || !esink->eo) {
856 GST_WARNING("there is no esink info.... esink : %p, or eo is NULL returning", esink);
859 if(esink->need_flush && esink->flush_buffer)
861 g_mutex_lock(esink->display_buffer_lock);
862 Evas_Native_Surface surf;
863 GstVideoRectangle result = {0};
865 evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h);
866 if (!esink->eo_size.w || !esink->eo_size.h) {
867 GST_ERROR ("there is no information for evas object size");
870 gst_evas_image_sink_update_geometry(esink, &result);
871 if(!result.w || !result.h)
873 GST_ERROR("no information about geometry (%d, %d)", result.w, result.h);
879 surf.data.tizen.ratio = (float) esink->w / esink->h;
880 GST_LOG("set ratio for letter mode");
882 evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL);
883 evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
884 if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) {
885 evas_object_image_size_set(esink->eo, esink->w, esink->h);
886 esink->is_evas_object_size_set = TRUE;
889 if(result.x || result.y)
890 GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y);
892 evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h);
894 surf.type = EVAS_NATIVE_SURFACE_TIZEN;
895 surf.version = EVAS_NATIVE_SURFACE_VERSION;
896 surf.data.tizen.buffer = esink->flush_buffer->n_buffer;
897 surf.data.tizen.rot = esink->rotate_angle;
898 surf.data.tizen.flip = esink->flip;
899 GST_DEBUG("use esink->flush buffer->n_buffer (%p), rotate(%d), flip(%d)",
900 esink->flush_buffer->n_buffer, esink->rotate_angle, esink->flip);
901 evas_object_image_native_surface_set(esink->eo, &surf);
902 g_mutex_unlock(esink->display_buffer_lock);
903 esink->need_flush = FALSE;
905 evas_object_image_pixels_dirty_set (esink->eo, EINA_TRUE);
906 GST_LOG("dirty set finish");
910 gst_evas_image_sink_release_source_buffer(GstEvasImageSink *esink)
913 tbm_bo_handle bo_handle;
914 g_mutex_lock(esink->display_buffer_lock);
916 for(i = 0; i < NATIVE_BUFFER_NUM; i++) {
917 GST_WARNING("[reset] reset gst %p", esink->displaying_buffer[i].buffer);
918 esink->displaying_buffer[i].bo = NULL;
919 esink->displaying_buffer[i].n_buffer = NULL;
920 esink->displaying_buffer[i].ref_count = 0;
923 for(i = 0; i < SOURCE_BUFFER_NUM; i++) {
924 if(esink->src_buffer_info[i].bo) {
925 tbm_bo_unmap(esink->src_buffer_info[i].bo);
926 esink->src_buffer_info[i].bo = NULL;
929 if (esink->src_buffer_info[i].n_buffer) {
930 native_buffer_destroy(esink->src_buffer_info[i].n_buffer);
931 esink->src_buffer_info[i].n_buffer = NULL;
935 if(esink->n_provider) {
936 native_buffer_provider_destroy(esink->n_provider);
937 esink->n_provider = NULL;
939 esink->is_buffer_allocated = FALSE;
940 esink->src_buf_idx = 0;
941 esink->prev_buf = NULL;
942 esink->prev_index = -1;
943 esink->cur_index = -1;
945 esink->eo_size.x = esink->eo_size.y =
946 esink->eo_size.w = esink->eo_size.h = 0;
947 esink->use_ratio = FALSE;
948 esink->sent_buffer_cnt = 0;
950 g_mutex_unlock(esink->display_buffer_lock);
956 gst_evas_image_sink_allocate_source_buffer(GstEvasImageSink *esink)
962 GstFlowReturn ret=GST_FLOW_OK;
965 GST_ERROR("handle is NULL");
969 /* create native buffer provider for making native buffer */
970 if(esink->n_provider) {
971 GST_INFO("Native buffer provider already exists. Skipping creating one.");
973 esink->n_provider = native_buffer_provider_create (NATIVE_BUFFER_PROVIDER_CORE);
974 if(!esink->n_provider) {
975 GST_ERROR("n_provider is NULL!!");
980 for(idx=0; idx < SOURCE_BUFFER_NUM; idx++) {
981 if(!esink->src_buffer_info[idx].n_buffer) {
982 /* create native buffer */
983 esink->src_buffer_info[idx].n_buffer = native_buffer_create(esink->n_provider, esink->w, esink->h, 0, esink->native_buffer_format,
984 NATIVE_BUFFER_USAGE_CPU|NATIVE_BUFFER_USAGE_3D_TEXTURE);
986 if(!esink->src_buffer_info[idx].n_buffer)
988 GST_ERROR("n_buffer is NULL!!");
992 /* get bo and size */
993 bo = native_buffer_get_bo(esink->src_buffer_info[idx].n_buffer);
994 size = tbm_bo_size(bo);
997 GST_ERROR("bo(%p), size(%d)", bo, size);
1000 esink->src_buffer_info[idx].bo = bo;
1002 vaddr = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
1004 GST_WARNING_OBJECT(esink, "get vaddr failed pointer = %p", vaddr.ptr);
1008 memset (vaddr.ptr, 0x0, size);
1009 GST_LOG_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr.ptr);
1012 esink->src_buffer_info[idx].usr_addr = vaddr.ptr;
1014 GST_WARNING_OBJECT(esink, "src buffer index:%d , native buffer : %p", idx, esink->src_buffer_info[idx].n_buffer);
1020 gst_evas_image_sink_release_source_buffer(esink);
1026 evas_image_sink_get_size_from_caps (GstCaps *caps, int *w, int *h)
1032 if (!caps || !w || !h) {
1035 s = gst_caps_get_structure (caps, 0);
1040 r = gst_structure_get_int (s, CAP_WIDTH, &width);
1042 GST_DEBUG("fail to get width from caps");
1046 r = gst_structure_get_int (s, CAP_HEIGHT, &height);
1048 GST_DEBUG("fail to get height from caps");
1054 GST_DEBUG ("size w(%d), h(%d)", width, height);
1060 is_zerocopy_supported (Evas *e)
1062 Eina_List *engines, *l;
1071 engines = evas_render_method_list ();
1076 cur_id = evas_output_method_get (e);
1078 EINA_LIST_FOREACH (engines, l, name) {
1079 id = evas_render_method_lookup (name);
1080 if (name && id == cur_id) {
1081 if (!strcmp (name, GL_X11_ENGINE)) {
1091 evas_image_sink_event_parse_data (GstEvasImageSink *esink, GstEvent *event)
1093 const GstStructure *st;
1094 guint st_data_addr = 0;
1095 gint st_data_width = 0;
1096 gint st_data_height = 0;
1098 g_return_val_if_fail (event != NULL, FALSE);
1099 g_return_val_if_fail (esink != NULL, FALSE);
1101 if (GST_EVENT_TYPE (event) != GST_EVENT_CUSTOM_DOWNSTREAM_OOB) {
1102 GST_WARNING ("it's not a custom downstream oob event");
1105 st = gst_event_get_structure (event);
1106 if (st == NULL || !gst_structure_has_name (st, "GstStructureForCustomEvent")) {
1107 GST_WARNING ("structure in a given event is not proper");
1110 if (!gst_structure_get_uint (st, "data-addr", &st_data_addr)) {
1111 GST_WARNING ("parsing data-addr failed");
1114 esink->present_data_addr = st_data_addr;
1120 gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event)
1123 GstEvasImageSink *esink = GST_EVASIMAGESINK (sink);
1127 switch (GST_EVENT_TYPE (event)) {
1128 case GST_EVENT_FLUSH_START:
1129 GST_DEBUG ("GST_EVENT_FLUSH_START");
1131 case GST_EVENT_FLUSH_STOP:
1132 GST_DEBUG ("GST_EVENT_FLUSH_STOP");
1135 GST_DEBUG ("GST_EVENT_EOS");
1138 case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
1139 if(!evas_image_sink_event_parse_data(esink, event)) {
1140 GST_DEBUG ("GST_EVENT_CUSTOM_DOWNSTREAM_OOB, present_data_addr:%x",esink->present_data_addr);
1142 GST_ERROR ("evas_image_sink_event_parse_data() failed");
1149 if (GST_BASE_SINK_CLASS (parent_class)->event) {
1150 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
1156 static GstStateChangeReturn
1157 gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition)
1159 GstStateChangeReturn ret_state = GST_STATE_CHANGE_SUCCESS;
1160 GstEvasImageSink *esink = NULL;
1161 GstFlowReturn ret=GST_FLOW_OK;
1162 esink = GST_EVASIMAGESINK(element);
1165 GST_ERROR("can not get evasimagesink from element");
1166 return GST_STATE_CHANGE_FAILURE;
1169 switch (transition) {
1170 case GST_STATE_CHANGE_NULL_TO_READY:
1171 GST_WARNING ("*** STATE_CHANGE_NULL_TO_READY ***");
1172 #ifdef USE_NATIVE_BUFFER
1173 g_mutex_lock (esink->flow_lock);
1174 if (!is_evas_image_object (esink->eo)) {
1175 GST_ERROR_OBJECT (esink, "There is no evas image object..");
1176 g_mutex_unlock (esink->flow_lock);
1177 return GST_STATE_CHANGE_FAILURE;
1179 g_mutex_unlock (esink->flow_lock);
1182 case GST_STATE_CHANGE_READY_TO_PAUSED:
1183 GST_WARNING ("*** STATE_CHANGE_READY_TO_PAUSED ***");
1185 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1186 #ifdef USE_NATIVE_BUFFER
1187 /* Print debug log for 8 frame */
1188 esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT;
1189 esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT;
1191 GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_PLAYING ***");
1197 ret_state = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1199 switch (transition) {
1200 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1201 GST_WARNING ("*** STATE_CHANGE_PLAYING_TO_PAUSED ***");
1203 case GST_STATE_CHANGE_PAUSED_TO_READY:
1204 GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_READY ***");
1205 #ifdef USE_NATIVE_BUFFER
1207 /* flush buffer, we will copy last buffer to keep image data and reset buffer list */
1208 GST_WARNING("esink->enable_flush_buffer : %d", esink->enable_flush_buffer);
1209 if(esink->enable_flush_buffer && esink->native_buffer_format == NATIVE_BUFFER_FORMAT_NV12)
1211 if (gst_esink_make_flush_buffer(esink) == FALSE) {
1212 ret = gst_esink_epipe_reset(esink);
1214 GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret);
1215 return GST_STATE_CHANGE_FAILURE;
1217 gst_evas_image_sink_reset(esink);
1221 ret = gst_esink_epipe_reset(esink);
1223 GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret);
1224 return GST_STATE_CHANGE_FAILURE;
1226 if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_NV12) {
1227 gst_evas_image_sink_reset(esink);
1228 } else if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_I420) {
1229 gst_evas_image_sink_release_source_buffer(esink);
1234 case GST_STATE_CHANGE_READY_TO_NULL:
1235 GST_WARNING ("*** STATE_CHANGE_READY_TO_NULL ***");
1236 #ifdef USE_NATIVE_BUFFER
1237 if(esink->flush_buffer)
1238 _release_flush_buffer(esink);
1239 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
1241 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
1243 GST_DEBUG("ecore-pipe will delete");
1244 ecore_pipe_del (esink->epipe);
1245 esink->epipe = NULL;
1256 gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
1258 GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
1261 g_mutex_lock (instance_lock);
1264 case PROP_EVAS_OBJECT:
1265 eo = g_value_get_pointer (value);
1266 if (is_evas_image_object (eo)) {
1267 if (eo != esink->eo) {
1269 #ifdef USE_NATIVE_BUFFER
1270 EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo));
1272 /* delete evas object callbacks registrated on a previous evas image object */
1273 EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo);
1275 /* add evas object callbacks on a new evas image object */
1276 EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo, esink);
1277 #ifdef USE_NATIVE_BUFFER
1278 GST_WARNING("register render callback [esink : %p, esink->eo : %x]", esink, esink->eo);
1279 EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo), esink);
1280 evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h);
1281 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);
1284 esink->gl_zerocopy = is_zerocopy_supported (evas_object_evas_get (eo));
1285 if (esink->gl_zerocopy) {
1286 evas_object_image_content_hint_set (esink->eo, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
1287 GST_DEBUG("Enable gl zerocopy");
1290 GST_DEBUG("Evas Image Object(%x) is set", esink->eo);
1291 esink->is_evas_object_size_set = FALSE;
1292 esink->object_show = TRUE;
1293 esink->update_visibility = UPDATE_TRUE;
1295 r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY);
1296 if (r == EINA_FALSE) {
1297 GST_WARNING ("Failed to ecore_pipe_write() for updating visibility\n");
1302 GST_ERROR ("Cannot set evas-object property: value is not an evas image object");
1306 case PROP_EVAS_OBJECT_SHOW:
1309 esink->object_show = g_value_get_boolean (value);
1310 if( !is_evas_image_object(esink->eo) ) {
1311 GST_WARNING ("Cannot apply visible(show-object) property: cannot get an evas object\n");
1314 esink->update_visibility = UPDATE_TRUE;
1315 GST_LOG("esink->update_visibility : %d", esink->update_visibility);
1317 r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY);
1318 if (r == EINA_FALSE) {
1319 GST_WARNING ("Failed to ecore_pipe_write() for updating visibility)\n");
1324 #ifdef USE_NATIVE_BUFFER
1325 case PROP_ROTATE_ANGLE:
1328 rotate = g_value_get_int (value);
1332 esink->rotate_angle = 0;
1335 esink->rotate_angle = 90;
1338 esink->rotate_angle = 180;
1341 esink->rotate_angle = 270;
1346 GST_INFO("update rotate_angle : %d", esink->rotate_angle);
1349 case PROP_DISPLAY_GEOMETRY_METHOD:
1352 guint geometry = g_value_get_int (value);
1353 if (esink->display_geometry_method != geometry) {
1354 esink->display_geometry_method = geometry;
1355 GST_INFO_OBJECT (esink, "Overlay geometry method update, display_geometry_method(%d)", esink->display_geometry_method);
1358 g_mutex_lock(esink->display_buffer_lock);
1360 if(esink->cur_index!=-1 && esink->epipe)
1362 GST_WARNING("apply property esink->cur_index =%d",esink->cur_index);
1363 esink->displaying_buffer[esink->cur_index].ref_count++;
1364 gst_buffer_ref(esink->displaying_buffer[esink->cur_index].buffer);
1365 esink->sent_buffer_cnt++;
1366 r = ecore_pipe_write (esink->epipe, &esink->cur_index, SIZE_FOR_NATIVE_INDEX);
1368 if (r == EINA_FALSE) {
1369 GST_WARNING("ecore_pipe_write fail");
1370 esink->displaying_buffer[esink->cur_index].ref_count--;
1371 gst_buffer_unref(esink->displaying_buffer[esink->cur_index].buffer);
1372 esink->sent_buffer_cnt--;
1375 g_mutex_unlock(esink->display_buffer_lock);
1378 case PROP_ENABLE_FLUSH_BUFFER:
1379 esink->enable_flush_buffer = g_value_get_boolean(value);
1383 esink->flip = g_value_get_int(value);
1384 GST_INFO("update flip : %d", esink->flip);
1389 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1393 g_mutex_unlock (instance_lock);
1397 gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1399 GstEvasImageSink *esink = GST_EVASIMAGESINK (object);
1402 case PROP_EVAS_OBJECT:
1403 g_value_set_pointer (value, esink->eo);
1405 case PROP_EVAS_OBJECT_SHOW:
1406 g_value_set_boolean (value, esink->object_show);
1408 #ifdef USE_NATIVE_BUFFER
1409 case PROP_ROTATE_ANGLE:
1410 g_value_set_int (value, esink->rotate_angle);
1412 case PROP_DISPLAY_GEOMETRY_METHOD:
1413 g_value_set_int (value, esink->display_geometry_method);
1415 case PROP_ENABLE_FLUSH_BUFFER:
1416 g_value_set_boolean(value, esink->enable_flush_buffer);
1419 g_value_set_int(value, esink->flip);
1423 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1429 gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps)
1433 GstEvasImageSink *esink = GST_EVASIMAGESINK (base_sink);
1434 GstStructure *structure = NULL;
1437 esink->is_evas_object_size_set = FALSE;
1438 r = evas_image_sink_get_size_from_caps (caps, &w, &h);
1442 GST_DEBUG ("set size w(%d), h(%d)", w, h);
1445 structure = gst_caps_get_structure (caps, 0);
1450 if (!gst_structure_get_fourcc (structure, "format", &format)) {
1451 GST_DEBUG ("format(dst) is not set...it may be rgb series");
1454 GST_DEBUG_OBJECT(esink, "source color format is %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (format));
1456 #ifdef USE_NATIVE_BUFFER
1457 if (format == GST_MAKE_FOURCC('S','N','1','2') || format == GST_MAKE_FOURCC('N','V','1','2') ) {
1458 esink->native_buffer_format = NATIVE_BUFFER_FORMAT_NV12;
1459 } else if (format == GST_MAKE_FOURCC('I','4','2','0')){
1460 esink->native_buffer_format = NATIVE_BUFFER_FORMAT_I420;
1462 GST_ERROR("cannot parse fourcc format from caps.");
1470 static GstFlowReturn
1471 gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf)
1473 GstEvasImageSink *esink = GST_EVASIMAGESINK (video_sink);
1476 GST_LOG("[ENTER] show frame");
1477 #ifdef USE_NATIVE_BUFFER
1478 if (!gst_evas_image_sink_ref_count (buf))
1480 GST_WARNING("ref count is 0.. skip show frame");
1484 g_mutex_lock (instance_lock);
1486 if (esink->present_data_addr == -1) {
1487 /* if present_data_addr is -1, we don't use this member variable */
1488 } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) {
1489 GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC);
1490 g_mutex_unlock (instance_lock);
1494 if (!esink->epipe) {
1495 esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink);
1496 if (!esink->epipe) {
1497 GST_ERROR ("ecore-pipe create failed");
1498 g_mutex_unlock (instance_lock);
1499 return GST_FLOW_ERROR;
1501 GST_DEBUG("ecore-pipe create success");
1503 #ifdef USE_NATIVE_BUFFER
1506 SCMN_IMGB *scmn_imgb = NULL;
1507 gboolean exist_bo = FALSE;
1509 GST_LOG ("BUF: gst_buf= %p ts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p",
1510 buf, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf), GST_BUFFER_MALLOCDATA(buf));
1512 if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_NV12) {
1513 /* get received buffer informations */
1514 scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
1516 GST_WARNING("scmn_imgb is NULL. Skip..." );
1517 g_mutex_unlock (instance_lock);
1520 if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER)
1522 /* check whether bo is new or not */
1523 for(i=0; i<NATIVE_BUFFER_NUM; i++)
1525 if(esink->displaying_buffer[i].bo==scmn_imgb->bo[0])
1527 GST_DEBUG("it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i);
1538 /* find empty buffer space for indexing */
1539 for(i=0; i<NATIVE_BUFFER_NUM; i++)
1541 if(!esink->displaying_buffer[i].bo)
1549 /* keep informations */
1550 esink->displaying_buffer[index].buffer = buf;
1551 esink->displaying_buffer[index].bo = scmn_imgb->bo[0];
1552 GST_WARNING("TBM bo %p / gst_buf %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer);
1554 /* create new native buffer */
1555 if(!esink->n_provider)
1557 GST_WARNING("native buffer provide don't exist... create it");
1558 esink->n_provider = native_buffer_provider_create (NATIVE_BUFFER_PROVIDER_CORE);
1560 esink->displaying_buffer[index].n_buffer = native_buffer_create_for_tbm(esink->n_provider, esink->displaying_buffer[index].bo, esink->w, esink->h, 0,
1561 NATIVE_BUFFER_FORMAT_NV12);
1562 if(!esink->displaying_buffer[index].n_buffer)
1564 GST_WARNING("there is no native buffer.. bo : %p, gst_buf : %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer);
1565 g_mutex_unlock (instance_lock);
1569 GST_WARNING("create native buffer : %p", esink->displaying_buffer[index].n_buffer);
1572 /* because it has same bo, use existing native buffer */
1577 esink->displaying_buffer[index].buffer = buf;
1578 GST_DEBUG("existing native buffer %p.. bo %p, gst_buf %p", esink->displaying_buffer[index].n_buffer, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer);
1583 /* if it couldn't find proper index */
1585 GST_WARNING("all spaces are using!!!");
1587 GST_DEBUG("selected buffer index %d", index);
1590 else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER)
1592 /* flush buffer, we will copy last buffer to keep image data and reset buffer list */
1593 GST_WARNING_OBJECT(esink, "FLUSH_BUFFER: gst_buf= %p ts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p",
1594 buf, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf), GST_BUFFER_MALLOCDATA(buf));
1595 gst_buffer_ref (buf);
1596 if (gst_esink_make_flush_buffer(esink))
1597 GST_WARNING("made flush buffer");
1598 gst_buffer_unref (buf);
1602 GST_ERROR("it is not TBM buffer.. %d", scmn_imgb->buf_share_method);
1604 } else if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_I420) {
1605 static int skip_count_i420=0;
1606 if(esink->sent_buffer_cnt >= MAX_ECOREPIPE_BUFFER_CNT) {
1607 if(!(skip_count_i420++%20)) {
1608 GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count_i420);
1610 g_mutex_unlock (instance_lock);
1614 if(!esink->is_buffer_allocated) {
1615 /* Allocate TBM buffer for non-zero copy case */
1616 if(!gst_evas_image_sink_allocate_source_buffer(esink)) {
1617 GST_ERROR_OBJECT(esink, "Buffer allocation failed");
1618 g_mutex_unlock (instance_lock);
1619 return GST_FLOW_ERROR;
1621 esink->is_buffer_allocated = TRUE;
1624 skip_count_i420 = 0; //for skip log in I420
1626 /* check whether bo is new or not */
1627 for(i=0; i<NATIVE_BUFFER_NUM; i++) {
1628 if(esink->displaying_buffer[i].bo == esink->src_buffer_info[esink->src_buf_idx].bo) {
1629 GST_DEBUG_OBJECT(esink, "it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i);
1640 /* find empty buffer space for indexing */
1641 for(i=0; i<NATIVE_BUFFER_NUM; i++) {
1642 if(!esink->displaying_buffer[i].bo) {
1649 /* keep informations */
1650 esink->displaying_buffer[index].bo = esink->src_buffer_info[esink->src_buf_idx].bo;
1651 esink->displaying_buffer[index].n_buffer = esink->src_buffer_info[esink->src_buf_idx].n_buffer;
1653 GST_DEBUG_OBJECT(esink, "gst_buf %p, TBM bo %p.. gst_buf vaddr %p .. src data size(%lu)",
1654 buf, esink->displaying_buffer[index].bo, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
1656 memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
1659 /* because it has same bo, use existing native buffer */
1661 memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
1663 GST_DEBUG_OBJECT(esink, "existing native buffer %p.. gst_buf %p, bo %p, gst_buf vaddr %p",
1664 esink->displaying_buffer[index].n_buffer, buf, esink->displaying_buffer[index].bo, GST_BUFFER_DATA(buf));
1669 /* if it couldn't find proper index */
1671 GST_WARNING_OBJECT(esink, "all spaces are being used!!!");
1673 GST_DEBUG_OBJECT(esink, "selected buffer index %d", index);
1676 GST_ERROR_OBJECT(esink, "unsupported color format");
1677 g_mutex_unlock (instance_lock);
1678 return GST_FLOW_ERROR;
1681 if (esink->object_show && index != -1) {
1683 gst_buffer_ref (buf);
1684 r = ecore_pipe_write (esink->epipe, &buf, sizeof (GstBuffer *));
1685 if (r == EINA_FALSE) {
1686 //add error handling
1687 GST_WARNING("ecore_pipe_write fail");
1690 #ifdef USE_NATIVE_BUFFER
1691 int old_curidx=esink->cur_index ;
1692 static int skip_count=0;
1693 g_mutex_lock(esink->display_buffer_lock);
1695 if(esink->native_buffer_format == NATIVE_BUFFER_FORMAT_NV12 && scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
1696 if (esink->sent_buffer_cnt < MAX_ECOREPIPE_BUFFER_CNT) {
1697 GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf);
1698 gst_buffer_ref (buf);
1699 esink->displaying_buffer[index].ref_count++;
1700 esink->cur_index = index;
1701 GST_LOG("index %d set refcount increase as %d", index,esink->displaying_buffer[index].ref_count);
1702 GST_LOG("[show_frame] after refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf);
1704 /* Print debug log for 8 frame */
1705 if(esink->debuglog_cnt_showFrame > 0)
1707 GST_WARNING("(%d) ecore_pipe_write index[%d] gst_buf : %p", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame),
1708 esink->cur_index, esink->displaying_buffer[esink->cur_index].buffer);
1709 esink->debuglog_cnt_showFrame--;
1712 esink->sent_buffer_cnt++;
1715 r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_NATIVE_INDEX);
1717 if (r == EINA_FALSE) {
1718 GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf);
1719 esink->cur_index = old_curidx;
1720 if(esink->displaying_buffer[index].ref_count)
1722 esink->displaying_buffer[index].ref_count--;
1723 esink->sent_buffer_cnt--;
1724 gst_buffer_unref(buf);
1725 GST_ERROR("finish unreffing");
1729 /* If buffer count which is sent to ecore pipe, is upper 3, Print Error log */
1730 if(!(skip_count++%20)) {
1731 GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count);
1734 } else if (esink->native_buffer_format == NATIVE_BUFFER_FORMAT_I420) {
1735 esink->cur_index = index;
1736 GST_LOG("index %d", index);
1737 GST_LOG("[show_frame] gst_buf vaddr %p", esink->src_buffer_info[esink->src_buf_idx].usr_addr);
1739 /* Print debug log for 8 frame */
1740 if(esink->debuglog_cnt_showFrame > 0)
1742 GST_WARNING("(%d) ecore_pipe_write : index[%d], bo[%p], n_buffer[%p], gst_buf[%p], gst_buf vaddr [%p]", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame),
1743 esink->cur_index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].n_buffer, buf, esink->src_buffer_info[esink->src_buf_idx].usr_addr);
1744 esink->debuglog_cnt_showFrame--;
1747 esink->sent_buffer_cnt++;
1749 esink->src_buf_idx++;
1750 r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_NATIVE_INDEX);
1752 if (r == EINA_FALSE) {
1753 esink->cur_index = old_curidx;
1754 esink->sent_buffer_cnt--;
1755 esink->src_buf_idx--;
1756 GST_ERROR("ecore_pipe_write is failed. index[%d], bo[%p], n_buffer[%p], gst_buf vaddr [%p]",
1757 index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].n_buffer, esink->src_buffer_info[esink->src_buf_idx].usr_addr);
1759 esink->src_buf_idx = esink->src_buf_idx % SOURCE_BUFFER_NUM;
1762 g_mutex_unlock(esink->display_buffer_lock);
1764 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));
1766 GST_WARNING ("skip ecore_pipe_write(). becuase of esink->object_show(%d) index(%d)", esink->object_show, index);
1768 g_mutex_unlock (instance_lock);
1769 GST_DEBUG ("Leave");
1772 #ifdef USE_NATIVE_BUFFER
1774 static GstFlowReturn
1775 gst_esink_epipe_reset(GstEvasImageSink *esink)
1777 if (esink == NULL) {
1778 GST_ERROR("handle is NULL");
1779 return GST_FLOW_ERROR;
1783 GST_DEBUG("ecore-pipe will delete");
1784 ecore_pipe_del (esink->epipe);
1785 esink->epipe = NULL;
1788 if (!esink->epipe) {
1789 esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink);
1790 if (!esink->epipe) {
1791 GST_ERROR ("ecore-pipe create failed");
1792 return GST_FLOW_ERROR;
1794 GST_DEBUG("ecore-pipe create success");
1801 static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink)
1803 GstEvasImageFlushBuffer *flush_buffer = NULL;
1804 GstEvasImageDisplayingBuffer *display_buffer = NULL;
1807 tbm_bo_handle vaddr_src;
1808 tbm_bo_handle vaddr_dst;
1809 GstFlowReturn ret=GST_FLOW_OK;
1812 if (esink == NULL) {
1813 GST_ERROR("handle is NULL");
1817 if (esink->cur_index == -1) {
1818 GST_WARNING_OBJECT(esink, "there is no remained buffer");
1822 if(esink->flush_buffer)
1823 _release_flush_buffer(esink);
1826 flush_buffer = (GstEvasImageFlushBuffer *)malloc(sizeof(GstEvasImageFlushBuffer));
1827 if (flush_buffer == NULL) {
1828 GST_ERROR_OBJECT(esink, "GstEvasImageFlushBuffer alloc failed");
1832 memset(flush_buffer, 0x0, sizeof(GstEvasImageFlushBuffer));
1834 display_buffer = &(esink->displaying_buffer[esink->cur_index]);
1835 GST_WARNING_OBJECT(esink, "cur_index [%d]",
1837 if(!display_buffer || !display_buffer->bo)
1839 GST_WARNING("display_buffer(%p) or bo (%p) is NULL!!", display_buffer, display_buffer->bo);
1840 goto FLUSH_BUFFER_FAILED;
1843 /* create native buffer provider for making native buffer */
1844 flush_buffer->n_provider = native_buffer_provider_create (NATIVE_BUFFER_PROVIDER_CORE);
1846 if(!flush_buffer->n_provider)
1848 GST_ERROR("n_provider is NULL!!");
1849 goto FLUSH_BUFFER_FAILED;
1852 /* create native buffer */
1853 flush_buffer->n_buffer = native_buffer_create(flush_buffer->n_provider, esink->w, esink->h, 0, NATIVE_BUFFER_FORMAT_NV12,
1854 NATIVE_BUFFER_USAGE_CPU|NATIVE_BUFFER_USAGE_3D_TEXTURE);
1855 if(!flush_buffer->n_buffer)
1857 GST_ERROR("n_buffer is NULL!!");
1858 goto FLUSH_BUFFER_FAILED;
1861 /* get bo and size */
1862 bo = native_buffer_get_bo(flush_buffer->n_buffer);
1863 size = tbm_bo_size(bo);
1866 GST_ERROR("bo(%p), size(%d)", bo, size);
1867 goto FLUSH_BUFFER_FAILED;
1869 flush_buffer->bo = bo;
1871 src_size = display_buffer->buffer->size;
1873 vaddr_src = tbm_bo_map(display_buffer->bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
1874 vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
1875 if (!vaddr_src.ptr || !vaddr_dst.ptr) {
1876 GST_WARNING_OBJECT(esink, "get vaddr failed src %p, dst %p", vaddr_src.ptr, vaddr_dst.ptr);
1877 if (vaddr_src.ptr) {
1878 tbm_bo_unmap(display_buffer->bo);
1880 if (vaddr_dst.ptr) {
1883 goto FLUSH_BUFFER_FAILED;
1885 memset (vaddr_dst.ptr, 0x0, size);
1886 GST_WARNING_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr_dst.ptr);
1890 memcpy(vaddr_dst.ptr, vaddr_src.ptr, src_size);
1892 tbm_bo_unmap(display_buffer->bo);
1895 GST_WARNING_OBJECT(esink, "copy done.. native buffer : %p src_size : %d", flush_buffer->n_buffer, src_size);
1897 esink->flush_buffer = flush_buffer;
1899 /* initialize buffer list */
1900 if (esink->object_show)
1901 esink->need_flush = TRUE;
1903 ret = gst_esink_epipe_reset(esink);
1905 GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret);
1908 GST_ERROR_OBJECT(esink, "evas epipe reset success");
1911 gst_evas_image_sink_reset(esink);
1916 FLUSH_BUFFER_FAILED:
1918 if(flush_buffer->n_buffer)
1920 native_buffer_destroy(flush_buffer->n_buffer);
1921 flush_buffer->n_buffer = NULL;
1923 if(flush_buffer->n_provider)
1925 native_buffer_provider_destroy(flush_buffer->n_provider);
1928 flush_buffer = NULL;
1933 static void _release_flush_buffer(GstEvasImageSink *esink)
1935 if (esink == NULL ||
1936 esink->flush_buffer == NULL) {
1937 GST_WARNING("handle is NULL");
1941 GST_WARNING_OBJECT(esink, "release FLUSH BUFFER start");
1942 if (esink->flush_buffer->bo) {
1943 esink->flush_buffer->bo = NULL;
1945 if(esink->flush_buffer->n_buffer) {
1946 native_buffer_destroy(esink->flush_buffer->n_buffer);
1947 esink->flush_buffer->n_buffer = NULL;
1949 if(esink->flush_buffer->n_provider) {
1950 native_buffer_provider_destroy(esink->flush_buffer->n_provider);
1953 GST_WARNING_OBJECT(esink, "release FLUSH BUFFER done");
1955 free(esink->flush_buffer);
1956 esink->flush_buffer = NULL;
1963 evas_image_sink_init (GstPlugin *evasimagesink)
1965 GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "Evas image object based videosink");
1967 return gst_element_register (evasimagesink, "evasimagesink", GST_RANK_NONE, GST_TYPE_EVASIMAGESINK);
1971 #define PACKAGE "gstevasimagesink-plugin-package"
1978 "Evas image object based videosink",
1979 evas_image_sink_init,
1982 "Samsung Electronics Co",
1983 "http://www.samsung.com/"