Change 'guint' variables to 'gint' and add valid geometry check
[platform/core/multimedia/libmm-evas-renderer.git] / src / mm_evas_renderer.c
1 /*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/syscall.h>
27 #include <dlog.h>
28 #include <mm_error.h>
29 #include <tbm_surface.h>
30 #include <tbm_surface_internal.h>
31
32 #include "mm_evas_renderer_private.h"
33
34 #ifdef LOG_TAG
35 #undef LOG_TAG
36 #endif
37 #define LOG_TAG "MM_EVAS_RENDER"
38
39 //#define _INTERNAL_DEBUG_ /* debug only */
40 #define SWAP(a, b)  ({int t; t = a; a = b; b = t; })
41 #define INIT_IDX -1
42 #define SIGNAL_TIMEOUT 1
43
44 #define MMER_FENTER();                                  LOGD("<ENTER>");
45 #define MMER_FLEAVE();                                  LOGD("<LEAVE>");
46
47 #define MMEVAS_RETURN_IF_FAIL(expr) \
48         do { \
49                 if (!(expr)) { \
50                         LOGW("faild [%s]", #expr); \
51                         return; \
52                 } \
53         } while (0)
54
55 #define MMEVAS_RETURN_VAL_IF_FAIL(expr, var) \
56         do { \
57                 if (!(expr)) { \
58                         LOGW("faild [%s]", #expr); \
59                         return (var); \
60                 } \
61         } while (0)
62
63 enum {
64         DISP_GEO_METHOD_LETTER_BOX = 0,
65         DISP_GEO_METHOD_ORIGIN_SIZE,
66         DISP_GEO_METHOD_FULL_SCREEN,
67         DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
68         DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
69         DISP_GEO_METHOD_CUSTOM_ROI,
70         DISP_GEO_METHOD_NUM,
71 };
72
73 enum {
74         DEGREE_0 = 0,
75         DEGREE_90,
76         DEGREE_180,
77         DEGREE_270,
78         DEGREE_NUM,
79 };
80
81 enum {
82         FLIP_NONE = 0,
83         FLIP_HORIZONTAL,
84         FLIP_VERTICAL,
85         FLIP_BOTH,
86         FLIP_NUM,
87 };
88
89 #ifdef _INTERNAL_DEBUG_
90 static int g_cnt_in = 0;
91 static int g_cnt_out = 0;
92 static int __dump_pkt(media_packet_h pkt, int width, int height);
93 static int __dump_surf(tbm_surface_h tbm_surf);
94 #endif
95 /* internal */
96 static void _free_previous_packets(mm_evas_info *evas_info);
97 static int _flush_all_packets(mm_evas_info *evas_info);
98 static int _mm_evas_renderer_create(mm_evas_info **evas_info);
99 static int _mm_evas_renderer_destroy(mm_evas_info **evas_info);
100 static int _mm_evas_renderer_set_info(mm_evas_info *evas_info, Evas_Object *eo);
101 static int _mm_evas_renderer_reset(mm_evas_info *evas_info, gboolean is_sub_thread);
102 static void _mm_evas_renderer_update_geometry(mm_evas_info *evas_info);
103 static int _mm_evas_renderer_retrieve_all_packets(mm_evas_info *evas_info, bool keep_screen);
104 static int _mm_evas_renderer_make_flush_buffer(mm_evas_info *evas_info);
105 static void _mm_evas_renderer_release_flush_buffer(mm_evas_info *evas_info);
106 static void _mm_evas_renderer_get_video_angle(mm_evas_info *evas_info, int *rotate_angle, int *orientation);
107 static void _mm_evas_renderer_update_rotate_angle(mm_evas_info *evas_info);
108 static void _mm_evas_renderer_set_callback(mm_evas_info *evas_info);
109 static void _mm_evas_renderer_unset_callback(mm_evas_info *evas_info);
110 static void _mm_evas_renderer_set_evas_object_size(mm_evas_info *evas_info);
111 static gboolean _check_rendering_packet(mm_evas_info *evas_info);
112
113 /* must be called after the null surface has been set. */
114 static int _mm_evas_renderer_update_rendering_info(mm_evas_info *evas_info)
115 {
116         MMER_FENTER();
117
118         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
119         MMEVAS_RETURN_VAL_IF_FAIL(evas_info->eo, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
120
121         evas_object_geometry_get(evas_info->eo, &evas_info->eo_size.x, &evas_info->eo_size.y, &evas_info->eo_size.w, &evas_info->eo_size.h);
122         if (!evas_info->eo_size.w || !evas_info->eo_size.h) {
123                 LOGE("there is no information for evas object size");
124                 return MM_ERROR_EVASRENDER_INTERNAL;
125         }
126         if (!evas_info->w || !evas_info->h) {
127                 LOGE("there is no video size from mm_evas_renderer_write() which is callback_func of player or camera");
128                 return MM_ERROR_EVASRENDER_INTERNAL;
129         }
130
131         _mm_evas_renderer_update_geometry(evas_info);
132         if (!evas_info->result.w || !evas_info->result.h) {
133                 LOGE("no information about geometry (%d, %d)", evas_info->result.w, evas_info->result.h);
134                 return MM_ERROR_EVASRENDER_INTERNAL;
135         }
136
137         if (evas_info->video_size_changed) {
138                 _mm_evas_renderer_set_evas_object_size(evas_info);
139                 evas_info->video_size_changed = FALSE;
140         }
141
142         if (evas_info->result.x || evas_info->result.y)
143                 LOGD("coordinate x, y (%d, %d) for locating video to center", evas_info->result.x, evas_info->result.y);
144         evas_object_image_fill_set(evas_info->eo, evas_info->result.x, evas_info->result.y, evas_info->result.w, evas_info->result.h);
145
146         MMER_FLEAVE();
147         return MM_ERROR_NONE;
148 }
149
150 static void _evas_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
151 {
152         /* now evas object size is changed */
153         mm_evas_info *evas_info = data;
154
155         MMER_FENTER();
156
157         MMEVAS_RETURN_IF_FAIL(evas_info);
158         MMEVAS_RETURN_IF_FAIL(evas_info->eo);
159
160         g_mutex_lock(&evas_info->idx_lock);
161
162         if (!_check_rendering_packet(evas_info)) {
163                 g_mutex_unlock(&evas_info->idx_lock);
164                 return;
165         }
166
167         g_mutex_unlock(&evas_info->idx_lock);
168
169         if (_mm_evas_renderer_update_rendering_info(evas_info) == MM_ERROR_NONE) {
170                 Evas_Native_Surface *surf;
171                 surf = evas_object_image_native_surface_get(evas_info->eo);
172                 if (surf) {
173                         LOGD("native surface exists");
174                         surf->data.tbm.rot = evas_info->rotate_angle;
175                         surf->data.tbm.flip = evas_info->flip;
176                         surf->data.tbm.ratio = evas_info->ratio;
177                         /* surface set must be called by main thread */
178                         evas_object_image_native_surface_set(evas_info->eo, surf);
179                 } else
180                         LOGW("there is no surf");
181         }
182
183         MMER_FLEAVE();
184 }
185
186 static gboolean _check_rendering_packet(mm_evas_info *evas_info)
187 {
188         gint cur_idx = 0;
189         tbm_format tbm_fmt = 0;
190         gchar *s_fmt = NULL;
191
192         MMER_FENTER();
193
194         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, FALSE);
195
196         cur_idx = evas_info->cur_idx;
197
198         if ((cur_idx == -1) || !evas_info->pkt_info[cur_idx].tbm_surf) {
199                 LOGW("cur_idx %d, tbm_surf may be NULL", cur_idx);
200                 return FALSE;
201         }
202
203         if (!evas_info->pkt_info[cur_idx].packet) {
204                 LOGE(" Packet is NULL");
205                 return FALSE;
206         }
207
208         tbm_fmt = tbm_surface_get_format(evas_info->pkt_info[cur_idx].tbm_surf);
209         switch (tbm_fmt) {
210         case TBM_FORMAT_NV12:
211                 s_fmt = "TBM_FORMAT_NV12";
212                 break;
213         case TBM_FORMAT_YUV420:
214                 s_fmt = "TBM_FORMAT_YUV420";
215                 break;
216         case TBM_FORMAT_YUYV:
217                 s_fmt = "TBM_FORMAT_YUYV";
218                 break;
219         default:
220                 s_fmt = "unknown";
221                 break;
222         }
223         LOGD("received idx(%d), packet(%p), format([%d]: %s)", cur_idx, evas_info->pkt_info[cur_idx].packet, tbm_fmt, s_fmt);
224
225         MMER_FLEAVE();
226
227         return TRUE;
228 }
229
230 /* must be called after the null surface has been set. */
231 static void _mm_evas_renderer_surface_set(mm_evas_info *evas_info)
232 {
233         gint cur_idx = 0;
234         gint prev_idx = 0;
235
236         MMER_FENTER();
237
238         MMEVAS_RETURN_IF_FAIL(evas_info);
239         MMEVAS_RETURN_IF_FAIL(evas_info->eo);
240
241         g_mutex_lock(&evas_info->idx_lock);
242
243         if (!_check_rendering_packet(evas_info)) {
244                 g_mutex_unlock(&evas_info->idx_lock);
245                 return;
246         }
247
248         if (evas_info->rendering_info_changed) {
249                 LOGD("Rendering info changed");
250                 if (_mm_evas_renderer_update_rendering_info(evas_info) != MM_ERROR_NONE)
251                         goto ERROR;
252                 evas_info->rendering_info_changed = FALSE;
253         }
254         LOGD("GEO_METHOD : src(%dx%d), dst(%dx%d), dst_x(%d), dst_y(%d), rotate(%d), flip(%d)", evas_info->w, evas_info->h, evas_info->eo_size.w, evas_info->eo_size.h, evas_info->eo_size.x, evas_info->eo_size.y, evas_info->rotate_angle, evas_info->flip);
255
256         if (evas_info->update_needed) {
257                 evas_object_image_native_surface_set(evas_info->eo, NULL);
258                 evas_info->update_needed = FALSE;
259         }
260
261         cur_idx = evas_info->cur_idx;
262         prev_idx = evas_info->pkt_info[cur_idx].prev_idx;
263
264         /* set surface */
265         Evas_Native_Surface surf = { 0 };
266         surf.type = EVAS_NATIVE_SURFACE_TBM;
267         surf.version = EVAS_NATIVE_SURFACE_VERSION;
268         surf.data.tbm.buffer = evas_info->pkt_info[cur_idx].tbm_surf;
269         surf.data.tbm.rot = evas_info->rotate_angle;
270         surf.data.tbm.flip = evas_info->flip;
271         surf.data.tbm.ratio = evas_info->ratio;
272
273 #ifdef _INTERNAL_DEBUG_
274         int ret2 = 0;
275         if ((g_cnt_out%5 == 0) && (g_cnt_out < 500))
276                 ret2 = __dump_surf(evas_info->pkt_info[cur_idx].tbm_surf);
277         if (ret2)
278                 LOGW("__dump_surf() is failed");
279         else
280                 g_cnt_out++;
281 #endif
282         if (evas_info->visible) {
283                 /* surface set must be called by main thread */
284                 evas_object_image_native_surface_set(evas_info->eo, &surf);
285                 evas_object_image_pixels_dirty_set(evas_info->eo, EINA_TRUE);
286                 LOGD("native surface set finish");
287         } else {
288                 LOGD("skip... surface set");
289         }
290
291         /* when _evas_pipe_cb is called sequentially, previous packet and current packet will be the same */
292         if ((prev_idx != -1) && evas_info->pkt_info[prev_idx].packet && (prev_idx != cur_idx))
293                 _free_previous_packets(evas_info);
294
295         g_mutex_unlock(&evas_info->idx_lock);
296
297         MMER_FLEAVE();
298         return;
299
300 ERROR:
301         if ((prev_idx != -1) && evas_info->pkt_info[prev_idx].packet) {
302                 LOGI("cant render");
303                 _free_previous_packets(evas_info);
304         }
305         g_mutex_unlock(&evas_info->idx_lock);
306
307         return;
308 }
309
310 /* must be called after the null surface has been set. */
311 static void _mm_evas_renderer_select_task(mm_evas_info *evas_info, update_info info)
312 {
313         MMER_FENTER();
314
315         MMEVAS_RETURN_IF_FAIL(evas_info);
316         MMEVAS_RETURN_IF_FAIL(evas_info->eo);
317
318         LOGD("evas_info : %p, info type : %d, evas_info->eo : %p", evas_info, info, evas_info->eo);
319
320         switch (info) {
321         case UPDATE_VISIBILITY:
322                 if (!evas_info->visible) {
323                         /* surface set must be called by main thread */
324                         evas_object_image_native_surface_set(evas_info->eo, NULL);
325                         evas_object_hide(evas_info->eo);
326                         LOGI("object hide..");
327                         LOGD("[LEAVE]");
328                 } else {
329                         evas_object_show(evas_info->eo);
330                         LOGI("object show.. %d", evas_info->visible);
331                         /* video rendering */
332                         _mm_evas_renderer_surface_set(evas_info);
333                 }
334                 break;
335         case UPDATE_TBM_SURF:
336                 /* video rendering */
337                 _mm_evas_renderer_surface_set(evas_info);
338                 break;
339         case UPDATE_FLUSH_BUFFER:
340                 if (_flush_all_packets(evas_info) != MM_ERROR_NONE)
341                         LOGE("flushing packets is failed");
342                 break;
343         default:
344                 LOGW("invalid info type : %d", info);
345                 break;
346         }
347
348         MMER_FLEAVE();
349         return;
350 }
351
352 static void _evas_pipe_cb(void *data, void *buffer, update_info info)
353 {
354         mm_evas_info *evas_info = data;
355
356         MMER_FENTER();
357
358         MMEVAS_RETURN_IF_FAIL(evas_info);
359         MMEVAS_RETURN_IF_FAIL(evas_info->eo);
360
361         LOGD("ecore_pipe is called");
362
363         if (!evas_info->is_set_resize_cb)
364                 _mm_evas_renderer_set_callback(evas_info);
365
366         g_mutex_lock(&evas_info->mp_lock);
367         _mm_evas_renderer_select_task(evas_info, info);
368         g_mutex_unlock(&evas_info->mp_lock);
369
370         MMER_FLEAVE();
371         return;
372 }
373
374 #ifdef _INTERNAL_DEBUG_
375 static int __dump_pkt(media_packet_h pkt, int width, int height)
376 {
377         uint8_t *data;
378         uint64_t size;
379         char filename[128] = {0};
380         FILE *fp = NULL;
381         int i = 0;
382         int stride_width, stride_height;
383         uint32_t plane_num = 0;
384
385         sprintf(filename, "/tmp/DUMP_IN_IMG_%2.2d.dump", g_cnt_in);
386         fp = fopen(filename, "wb");
387         if (fp == NULL)
388                 return 1;
389
390         media_packet_get_number_of_video_planes(pkt, &plane_num); /* temporary expedient to decide format */
391         media_packet_get_video_plane_data_ptr(pkt, 0, (void **)&data);
392         media_packet_get_video_stride_width(pkt, 0, &stride_width);
393         media_packet_get_video_stride_height(pkt, 0, &stride_height);
394         media_packet_get_buffer_size(pkt, &size);
395         LOGI("[0]stride : %d, %d", stride_width, stride_height);
396
397         for (i = 0; i < height; i++) {
398                 fwrite(data, width, 1, fp);
399                 data += stride_width;
400         }
401         if (plane_num == 2) { /* hw codec(NV12) */
402                 media_packet_get_video_plane_data_ptr(pkt, 1, (void **)&data);
403                 media_packet_get_video_stride_width(pkt, 1, &stride_width);
404                 for (i = 0; i < height/2; i++) {
405                         fwrite(data, width, 1, fp);
406                         data += stride_width;
407                 }
408         } else if (plane_num == 3) { /* sw codec(YUV420) */
409                 media_packet_get_video_plane_data_ptr(pkt, 1, (void **)&data);
410                 media_packet_get_video_stride_width(pkt, 1, &stride_width);
411                 for (i = 0; i < height/2; i++) {
412                         fwrite(data, width/2, 1, fp);
413                         data += stride_width;
414                 }
415                 LOGI("[1]stride : %d, %d", stride_width, stride_height);
416                 media_packet_get_video_plane_data_ptr(pkt, 2, (void **)&data);
417                 media_packet_get_video_stride_width(pkt, 2, &stride_width);
418                 for (i = 0; i < height/2; i++) {
419                         fwrite(data, width/2, 1, fp);
420                         data += stride_width;
421                 }
422                 LOGI("[2]stride : %d, %d", stride_width, stride_height);
423         } else {
424                 LOGW("plane_num %d", plane_num);
425                 fclose(fp);
426                 return 1;
427         }
428
429         LOGI("DUMP_IN_IMG_%2.2d : buffer size(%d) data(%p)", g_cnt_in, (int)size, data);
430         fclose(fp);
431
432         return 0;
433 }
434
435 static int __dump_surf(tbm_surface_h tbm_surf)
436 {
437         char filename[128] = {0};
438         tbm_surface_info_s info = {0};
439
440         sprintf(filename, "DUMP_OUT_IMG_%2.2d", g_cnt_out);
441         if (tbm_surface_get_info(tbm_surf, &info)) {
442                 LOGE("get_info is failed");
443                 return 1;
444         }
445
446         tbm_surface_internal_dump_start("/tmp", info.width, info.height, 1);
447         tbm_surface_internal_dump_buffer(tbm_surf, filename);
448         tbm_surface_internal_dump_end();
449
450         LOGI("[0]stride : %d, offset : %d", (int)info.planes[0].stride, (int)info.planes[0].offset);
451         LOGI("[1]stride : %d, offset : %d", (int)info.planes[1].stride, (int)info.planes[1].offset);
452         LOGI("[2]stride : %d, offset : %d", (int)info.planes[2].stride, (int)info.planes[2].offset);
453         LOGI("DUMP_OUT_IMG_%2.2d : buffer size(%d) surf(%p) %d*%d", g_cnt_out, (int)info.size, tbm_surf, info.width, info.height);
454
455         return 0;
456 }
457 #endif
458
459 static void _free_previous_packets(mm_evas_info *evas_info)
460 {
461         gint index = evas_info->cur_idx;
462         gint prev_idx = evas_info->pkt_info[index].prev_idx;
463
464         MMER_FENTER();
465
466         while (prev_idx != -1) {
467                 LOGD("destroy previous packet [%p] idx %d", evas_info->pkt_info[prev_idx].packet, prev_idx);
468                 if (evas_info->packet_rendered_cb) {
469                         evas_info->packet_rendered_cb(evas_info->pkt_info[prev_idx].packet, evas_info->packet_rendered_cb_user);
470                 } else {
471                         if (media_packet_destroy(evas_info->pkt_info[prev_idx].packet) != MEDIA_PACKET_ERROR_NONE)
472                                 LOGE("media_packet_destroy failed %p", evas_info->pkt_info[prev_idx].packet);
473                 }
474                 evas_info->sent_buffer_cnt--;
475                 evas_info->pkt_info[prev_idx].packet = NULL;
476                 evas_info->pkt_info[prev_idx].tbm_surf = NULL;
477                 evas_info->pkt_info[index].prev_idx = -1;
478
479                 /* move index to previous index */
480                 index = prev_idx;
481                 prev_idx = evas_info->pkt_info[prev_idx].prev_idx;
482                 LOGD("sent packet %d", evas_info->sent_buffer_cnt);
483         }
484
485         MMER_FLEAVE();
486
487         return;
488 }
489
490 static bool _get_video_size(media_packet_h packet, mm_evas_info *evas_info)
491 {
492         media_format_h fmt;
493         int w, h;
494         bool ret = true;
495
496         MMEVAS_RETURN_VAL_IF_FAIL(packet, false);
497         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, false);
498
499         if (media_packet_get_format(packet, &fmt) != MEDIA_PACKET_ERROR_NONE) {
500                 LOGE("media_packet_get_format is failed");
501                 return false;
502         }
503
504         if (media_format_get_video_info(fmt, NULL, &w, &h, NULL, NULL) != MEDIA_FORMAT_ERROR_NONE) {
505                 LOGE("media_format_get_video_info is failed");
506                 ret = false;
507                 goto end;
508         }
509
510         if (w != evas_info->w || h != evas_info->h) {
511                 LOGD("previous: (%dx%d)", evas_info->w, evas_info->w);
512                 evas_info->w = w;
513                 evas_info->h = h;
514                 evas_info->rendering_info_changed = TRUE;
515                 evas_info->video_size_changed = TRUE;
516         }
517         LOGD("(%dx%d)", evas_info->w, evas_info->w);
518
519 end:
520         if (media_format_unref(fmt) != MEDIA_FORMAT_ERROR_NONE)
521                 LOGW("media_format_unref is failed");
522
523         return ret;
524 }
525
526 static int _find_empty_index(mm_evas_info *evas_info)
527 {
528         int i;
529
530         MMER_FENTER();
531
532         for (i = 0; i < MAX_PACKET_NUM; i++) {
533                 if (!evas_info->pkt_info[i].packet) {
534                         LOGD("selected idx %d", i);
535                         return i;
536                 }
537         }
538         LOGE("there is no empty idx");
539
540         MMER_FLEAVE();
541
542         return -1;
543 }
544
545 /* must be called after the null surface has been set. */
546 static int _destroy_all_packets(mm_evas_info *evas_info)
547 {
548         int ret = MM_ERROR_NONE;
549         int ret_mp = MEDIA_PACKET_ERROR_NONE;
550         int i = 0;
551
552         MMER_FENTER();
553
554         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
555
556         g_mutex_lock(&evas_info->idx_lock);
557         for (i = 0; i < MAX_PACKET_NUM; i++) {
558                 if (evas_info->pkt_info[i].packet) {
559                         /* destroy all packets */
560                         LOGD("destroy packet [%p]", evas_info->pkt_info[i].packet);
561                         if (evas_info->packet_rendered_cb) {
562                                 evas_info->packet_rendered_cb(evas_info->pkt_info[i].packet, evas_info->packet_rendered_cb_user);
563                         } else {
564                                 ret_mp = media_packet_destroy(evas_info->pkt_info[i].packet);
565                                 if (ret_mp != MEDIA_PACKET_ERROR_NONE) {
566                                         LOGW("media_packet_destroy failed %p", evas_info->pkt_info[i].packet);
567                                         ret = MM_ERROR_EVASRENDER_INTERNAL;
568                                 }
569                         }
570                         evas_info->sent_buffer_cnt--;
571                         evas_info->pkt_info[i].packet = NULL;
572                         evas_info->pkt_info[i].tbm_surf = NULL;
573                         evas_info->pkt_info[i].prev_idx = INIT_IDX;
574                 }
575         }
576
577         if (evas_info->sent_buffer_cnt != 0)
578                 LOGE("it should be 0 --> [%d]", evas_info->sent_buffer_cnt);
579         evas_info->sent_buffer_cnt = 0;
580         evas_info->cur_idx = INIT_IDX;
581         evas_info->flush_all_packets = TRUE;
582
583         g_mutex_unlock(&evas_info->idx_lock);
584
585         MMER_FLEAVE();
586
587         return ret;
588
589 }
590
591 static int _set_flush_buffer(mm_evas_info *evas_info)
592 {
593         int ret = MM_ERROR_NONE;
594         Evas_Native_Surface surf = { 0 };
595
596         MMER_FENTER();
597
598         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
599
600         /* set flush buffer surface*/
601         surf.type = EVAS_NATIVE_SURFACE_TBM;
602         surf.version = EVAS_NATIVE_SURFACE_VERSION;
603         surf.data.tbm.buffer = evas_info->flush_buffer->tbm_surf;
604         surf.data.tbm.rot = evas_info->rotate_angle;
605         surf.data.tbm.flip = evas_info->flip;
606         surf.data.tbm.ratio = evas_info->ratio;
607
608         /* surface set must be called by main thread */
609         evas_object_image_native_surface_set(evas_info->eo, &surf);
610         evas_object_image_pixels_dirty_set(evas_info->eo, EINA_TRUE);
611
612         LOGD("flush_buffer surf(%p), rotate(%d), flip(%d)", evas_info->flush_buffer->tbm_surf, evas_info->rotate_angle, evas_info->flip);
613
614         return ret;
615 }
616
617 /* EVAS API must be called by main thread */
618 static int _flush_all_packets(mm_evas_info *evas_info)
619 {
620         int ret = MM_ERROR_NONE;
621
622         MMER_FENTER();
623
624         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
625         MMEVAS_RETURN_VAL_IF_FAIL(evas_info->eo, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
626
627         /* update the screen only if visible is true */
628         /* if flush buffer is null, we cant keep screen */
629         if (evas_info->keep_screen && evas_info->visible && evas_info->flush_buffer) {
630                 /* _set_flush_buffer */
631                 ret = _set_flush_buffer(evas_info);
632                 if (ret != MM_ERROR_NONE) return ret;
633         } else {
634                 /* unset evas native surface for removing rendered video frame */
635                 evas_object_image_native_surface_set(evas_info->eo, NULL);
636                 evas_object_image_pixels_dirty_set(evas_info->eo, EINA_TRUE);
637                 _mm_evas_renderer_unset_callback(evas_info);
638         }
639
640         LOGD("sent packet %d", evas_info->sent_buffer_cnt);
641         ret = _destroy_all_packets(evas_info);
642
643         if (ret == MM_ERROR_NONE) {
644                 g_mutex_lock(&evas_info->evas_lock);
645                 LOGD("send signal[COND_RETRIEVE]");
646                 g_cond_signal(&evas_info->evas_cond[COND_RETRIEVE]);
647                 g_mutex_unlock(&evas_info->evas_lock);
648         }
649
650         MMER_FLEAVE();
651
652         return ret;
653 }
654
655 static void _mm_evas_renderer_set_callback(mm_evas_info *evas_info)
656 {
657         MMER_FENTER();
658
659         if (evas_info->eo) {
660                 LOGD("resize callback add");
661                 evas_object_event_callback_add(evas_info->eo, EVAS_CALLBACK_RESIZE, _evas_resize_cb, evas_info);
662                 evas_info->is_set_resize_cb = TRUE;
663         }
664
665         MMER_FLEAVE();
666 }
667
668 static void _mm_evas_renderer_unset_callback(mm_evas_info *evas_info)
669 {
670         MMER_FENTER();
671
672         if (evas_info->eo) {
673                 LOGD("resize callback del");
674                 evas_object_event_callback_del(evas_info->eo, EVAS_CALLBACK_RESIZE, _evas_resize_cb);
675                 evas_info->is_set_resize_cb = FALSE;
676         }
677
678         MMER_FLEAVE();
679 }
680
681 static void _mm_evas_renderer_set_evas_object_size(mm_evas_info *evas_info)
682 {
683         MMER_FENTER();
684
685         MMEVAS_RETURN_IF_FAIL(evas_info);
686         MMEVAS_RETURN_IF_FAIL(evas_info->eo);
687
688         if (evas_info->w > 0 && evas_info->h > 0)
689                 evas_object_image_size_set(evas_info->eo, evas_info->w, evas_info->h);
690         evas_object_size_hint_align_set(evas_info->eo, EVAS_HINT_FILL, EVAS_HINT_FILL);
691         evas_object_size_hint_weight_set(evas_info->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
692
693         MMER_FLEAVE();
694
695         return;
696 }
697
698 static int _mm_evas_pipe_write(mm_evas_info *evas_info, update_info info)
699 {
700         int ret = MM_ERROR_NONE;
701
702         MMER_FENTER();
703
704         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
705         MMEVAS_RETURN_VAL_IF_FAIL(evas_info->epipe, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
706
707         g_mutex_lock(&evas_info->write_lock);
708         if (!ecore_pipe_write(evas_info->epipe, evas_info, info)) {
709                 LOGW("fail to ecore_pipe_write() for update info type(%d)", info);
710                 ret = MM_ERROR_EVASRENDER_INTERNAL;
711         }
712         g_mutex_unlock(&evas_info->write_lock);
713
714         MMER_FLEAVE();
715
716         return ret;
717 }
718
719 static int _mm_evas_renderer_create(mm_evas_info **evas_info)
720 {
721         mm_evas_info *ptr = NULL;
722
723         MMER_FENTER();
724
725         ptr = g_malloc0(sizeof(mm_evas_info));
726
727         if (!ptr) {
728                 LOGE("Cannot allocate memory for evas_info\n");
729                 goto ERROR;
730         } else {
731                 *evas_info = ptr;
732                 LOGD("Success create evas_info(%p)", *evas_info);
733         }
734         g_mutex_init(&ptr->mp_lock);
735         g_mutex_init(&ptr->idx_lock);
736         g_mutex_init(&ptr->write_lock);
737         g_mutex_init(&ptr->evas_lock);
738         g_cond_init(&ptr->evas_cond[COND_RETRIEVE]);
739         g_cond_init(&ptr->evas_cond[COND_DESTROY]);
740
741         MMER_FLEAVE();
742
743         return MM_ERROR_NONE;
744
745  ERROR:
746         *evas_info = NULL;
747         return MM_ERROR_EVASRENDER_NO_FREE_SPACE;
748 }
749
750 static int _mm_evas_renderer_destroy(mm_evas_info **evas_info)
751 {
752         int ret = MM_ERROR_NONE;
753         mm_evas_info *ptr = (mm_evas_info *)*evas_info;
754
755         MMER_FENTER();
756
757         MMEVAS_RETURN_VAL_IF_FAIL(ptr, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
758
759         LOGD("finalize evas_info %p", ptr);
760
761         ret = _mm_evas_renderer_reset(ptr, FALSE);
762         if (ret != MM_ERROR_NONE)
763                 LOGE("_mm_evas_renderer_reset is failed");
764
765         g_mutex_clear(&ptr->mp_lock);
766         g_mutex_clear(&ptr->idx_lock);
767         g_mutex_clear(&ptr->write_lock);
768         g_mutex_clear(&ptr->evas_lock);
769         g_cond_clear(&ptr->evas_cond[COND_RETRIEVE]);
770         g_cond_clear(&ptr->evas_cond[COND_DESTROY]);
771
772         g_free(ptr);
773         ptr = NULL;
774
775         MMER_FLEAVE();
776
777         return ret;
778 }
779
780 static int _mm_evas_renderer_set_info(mm_evas_info *evas_info, Evas_Object *eo)
781 {
782         int i;
783
784         MMER_FENTER();
785
786         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
787         MMEVAS_RETURN_VAL_IF_FAIL(eo, MM_ERROR_EVASRENDER_INVALID_ARGUMENT);
788
789         g_mutex_lock(&evas_info->idx_lock);
790
791         LOGD("set evas_info");
792
793         for (i = 0; i < MAX_PACKET_NUM; i++) {
794                 evas_info->pkt_info[i].packet = NULL;
795                 evas_info->pkt_info[i].tbm_surf = NULL;
796                 evas_info->pkt_info[i].prev_idx = -1;
797         }
798
799         evas_info->flush_all_packets = FALSE;
800         evas_info->rendering_info_changed = FALSE;
801         evas_info->video_size_changed = FALSE;
802         evas_info->w = evas_info->h = 0;
803         evas_info->cur_idx = -1;
804         evas_info->dst_roi.x = evas_info->dst_roi.y = evas_info->dst_roi.w = evas_info->dst_roi.h = 0;
805         evas_info->is_set_roi_area = FALSE;
806         evas_info->is_set_resize_cb = FALSE;
807         evas_info->display_geometry_method = evas_info->pre_display_geometry_method = DISP_GEO_METHOD_LETTER_BOX;
808         evas_info->eo = eo;
809         evas_info->epipe = ecore_pipe_add((Ecore_Pipe_Cb) _evas_pipe_cb, evas_info);
810         if (!evas_info->epipe) {
811                 LOGE("pipe is not created");
812                 g_mutex_unlock(&evas_info->idx_lock);
813                 return MM_ERROR_EVASRENDER_INTERNAL;
814         }
815         LOGD("created pipe %p", evas_info->epipe);
816
817         evas_object_geometry_get(evas_info->eo, &evas_info->eo_size.x, &evas_info->eo_size.y, &evas_info->eo_size.w, &evas_info->eo_size.h);
818         LOGI("evas object %p (%d, %d, %d, %d)", evas_info->eo, evas_info->eo_size.x, evas_info->eo_size.y, evas_info->eo_size.w, evas_info->eo_size.h);
819
820         g_mutex_unlock(&evas_info->idx_lock);
821
822         MMER_FLEAVE();
823
824         return MM_ERROR_NONE;
825 }
826
827 static int _mm_evas_renderer_reset(mm_evas_info *evas_info, gboolean is_sub_thread)
828 {
829         int ret = MM_ERROR_NONE;
830
831         MMER_FENTER();
832
833         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
834         MMEVAS_RETURN_VAL_IF_FAIL(evas_info->eo, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
835
836         g_mutex_lock(&evas_info->mp_lock);
837
838         evas_info->eo_size.x = evas_info->eo_size.y = evas_info->eo_size.w = evas_info->eo_size.h = 0;
839         evas_info->dst_roi.x = evas_info->dst_roi.y = evas_info->dst_roi.w = evas_info->dst_roi.h = 0;
840         evas_info->w = evas_info->h = 0;
841
842         if (evas_info->flush_buffer)
843                 _mm_evas_renderer_release_flush_buffer(evas_info);
844
845         if (evas_info->eo)
846                 evas_info->eo = NULL;
847
848         if (evas_info->epipe) {
849                 LOGD("pipe %p will be deleted", evas_info->epipe);
850                 ecore_pipe_del(evas_info->epipe);
851                 evas_info->epipe = NULL;
852         }
853
854         if (is_sub_thread) {
855                 g_mutex_lock(&evas_info->evas_lock);
856                 LOGD("send signal[COND_DESTROY]");
857                 g_cond_signal(&evas_info->evas_cond[COND_DESTROY]);
858                 g_mutex_unlock(&evas_info->evas_lock);
859         }
860
861         g_mutex_unlock(&evas_info->mp_lock);
862
863         MMER_FLEAVE();
864
865         return ret;
866 }
867
868 static void _mm_evas_renderer_update_geometry(mm_evas_info *evas_info)
869 {
870         gint video_width = 0;
871         gint video_height = 0;
872         rect_info result = { 0 };
873         gint disp_mode = -1;
874
875         MMER_FENTER();
876
877         MMEVAS_RETURN_IF_FAIL(evas_info);
878         MMEVAS_RETURN_IF_FAIL(evas_info->eo); //need to check evas object
879
880         /* get rotate angle with content orientaion */
881         _mm_evas_renderer_update_rotate_angle(evas_info);
882
883         result.x = 0;
884         result.y = 0;
885         video_width = evas_info->w;
886         video_height = evas_info->h;
887
888         /* Only SWAP is needed for result coordination calculation */
889         if (evas_info->rotate_angle == DEGREE_90 || evas_info->rotate_angle == DEGREE_270) {
890                 SWAP(video_width, video_height);
891 #ifdef _INTERNAL_DEBUG_
892                 LOGD("swapped width %d, height %d", video_width, video_height);
893 #endif
894         }
895         LOGD("eo size (x:%d,y:%d,w:%d,h:%d)", evas_info->eo_size.x, evas_info->eo_size.y, evas_info->eo_size.w, evas_info->eo_size.h);
896         LOGD("video size (w:%d,h:%d)", video_width, video_height);
897
898         if (evas_info->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI && evas_info->is_set_roi_area == FALSE) {
899                 disp_mode = evas_info->pre_display_geometry_method;
900                 LOGD("ROI area isn't set. and use previous display geometry method(%d)", disp_mode);
901         } else {
902                 disp_mode = evas_info->display_geometry_method;
903         }
904         switch (disp_mode) {
905         case DISP_GEO_METHOD_LETTER_BOX:
906                 /* set black padding for letter box mode */
907                 LOGD("letter box mode");
908                 evas_info->ratio = (float) evas_info->w / evas_info->h; /* need to set original video ratio */
909                 result.w = evas_info->eo_size.w;
910                 result.h = evas_info->eo_size.h;
911                 break;
912         case DISP_GEO_METHOD_ORIGIN_SIZE:
913                 LOGD("origin size mode");
914                 evas_info->ratio = 0;
915                 /* set coordinate for each case */
916                 result.x = (evas_info->eo_size.w - video_width) / 2;
917                 result.y = (evas_info->eo_size.h - video_height) / 2;
918                 result.w = video_width;
919                 result.h = video_height;
920                 break;
921         case DISP_GEO_METHOD_FULL_SCREEN:
922                 LOGD("full screen mode");
923                 evas_info->ratio = 0;
924                 result.w = evas_info->eo_size.w;
925                 result.h = evas_info->eo_size.h;
926                 break;
927         case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
928                 LOGD("cropped full screen mode");
929                 evas_info->ratio = 0;
930                 float eo_ratio = (float)evas_info->eo_size.w / evas_info->eo_size.h;
931                 float video_ratio = (float)video_width / video_height;
932                 /* compare evas object's ratio with video's */
933                 if (eo_ratio > video_ratio) {
934                         result.w = evas_info->eo_size.w;
935                         result.h = evas_info->eo_size.w * video_height / video_width;
936                         result.y = -(result.h - evas_info->eo_size.h) / 2;
937                 } else {
938                         result.w = evas_info->eo_size.h * video_width / video_height;
939                         result.h = evas_info->eo_size.h;
940                         result.x = -(result.w - evas_info->eo_size.w) / 2;
941                 }
942                 break;
943         case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
944                 /* if video size is smaller than evas object's, it will be set to origin size mode */
945                 if ((evas_info->eo_size.w > video_width) && (evas_info->eo_size.h > video_height)) {
946                         LOGD("origin size or letter box mode : set origin size mode");
947                         evas_info->ratio = 0;
948                         result.x = (evas_info->eo_size.w - video_width) / 2;
949                         result.y = (evas_info->eo_size.h - video_height) / 2;
950                         result.w = video_width;
951                         result.h = video_height;
952                 } else {
953                         LOGD("origin size or letter box mode : set letter box mode");
954                         evas_info->ratio = (float) evas_info->w / evas_info->h; /* need to set original video ratio */
955                         result.w = evas_info->eo_size.w;
956                         result.h = evas_info->eo_size.h;
957                 }
958                 break;
959         case DISP_GEO_METHOD_CUSTOM_ROI:
960                 LOGD("custom roi mode");
961                 if (evas_info->is_set_roi_area == FALSE) {
962                         LOGW("ROI Area isn't set");
963                         return;
964                 }
965                 /* roi need to set -1 */
966                 evas_info->ratio = -1;
967                 result.x = evas_info->dst_roi.x;
968                 result.y = evas_info->dst_roi.y;
969                 result.w = evas_info->dst_roi.w;
970                 result.h = evas_info->dst_roi.h;
971                 if (evas_info->rotate_angle == DEGREE_90 || evas_info->rotate_angle == DEGREE_270)
972                         SWAP(result.w, result.h);
973                 break;
974         default:
975                 LOGW("unsupported mode.");
976                 break;
977         }
978
979         evas_info->result.x = result.x;
980         evas_info->result.y = result.y;
981         evas_info->result.w = result.w;
982         evas_info->result.h = result.h;
983
984         LOGD("geometry result [%d, %d, %d, %d]", evas_info->result.x, evas_info->result.y, evas_info->result.w, evas_info->result.h);
985
986         MMER_FLEAVE();
987 }
988
989 static int _mm_evas_renderer_retrieve_all_packets(mm_evas_info *evas_info, bool keep_screen)
990 {
991         int ret = MM_ERROR_NONE;
992         pid_t pid = getpid();
993         pid_t tid = syscall(SYS_gettid);
994         gint64 end_time = g_get_monotonic_time() + SIGNAL_TIMEOUT * G_TIME_SPAN_SECOND;
995
996         MMER_FENTER();
997
998         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
999
1000         /* this API can be call by sub thread */
1001         LOGD("pid [%d], tid [%d]", pid, tid);
1002
1003         /* make flush buffer */
1004         if (keep_screen)
1005                 ret = _mm_evas_renderer_make_flush_buffer(evas_info);
1006         evas_info->keep_screen = keep_screen;
1007
1008         if (pid == tid) { /* API call by main thread */
1009                 /* flush all packet */
1010                 g_mutex_lock(&evas_info->mp_lock);
1011                 ret = _flush_all_packets(evas_info);
1012                 if (ret != MM_ERROR_NONE)
1013                         LOGE("flushing packets is failed");
1014                 g_mutex_unlock(&evas_info->mp_lock);
1015         } else {
1016                 /* flush all packet */
1017                 g_mutex_lock(&evas_info->evas_lock);
1018                 ret = _mm_evas_pipe_write(evas_info, UPDATE_FLUSH_BUFFER);
1019                 if (ret == MM_ERROR_NONE) {
1020                         if (!g_cond_wait_until(&evas_info->evas_cond[COND_RETRIEVE], &evas_info->evas_lock, end_time)) {
1021                                 //timeout
1022                                 LOGW("timeout: main thread is busy, App need to handle main thread well.");
1023                         }
1024                 }
1025                 g_mutex_unlock(&evas_info->evas_lock);
1026         }
1027
1028         MMER_FLEAVE();
1029
1030         return ret;
1031 }
1032
1033 /* make buffer for copying */
1034 static int _mm_evas_renderer_make_flush_buffer(mm_evas_info *evas_info)
1035 {
1036         MMER_FENTER();
1037
1038         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1039
1040         if (evas_info->cur_idx == -1) {
1041                 /* it is deemed ERROR_NONE, because this API is used only for retrieving buffers */
1042                 LOGW("there is no remaining buffer");
1043                 return MM_ERROR_NONE;
1044         }
1045         media_packet_h packet = evas_info->pkt_info[evas_info->cur_idx].packet;
1046         MMEVAS_RETURN_VAL_IF_FAIL(packet, MM_ERROR_EVASRENDER_INTERNAL);
1047
1048         flush_info *flush_buffer = NULL;
1049         tbm_surface_h src_tbm_surf = NULL;
1050         tbm_surface_info_s src_info = {0};
1051         tbm_surface_info_s dst_info = {0};
1052         int ret = MM_ERROR_NONE;
1053
1054         if (evas_info->flush_buffer)
1055                 _mm_evas_renderer_release_flush_buffer(evas_info);
1056
1057         /* malloc buffer */
1058         flush_buffer = (flush_info *)malloc(sizeof(flush_info));
1059         if (flush_buffer == NULL) {
1060                 LOGE("malloc is failed");
1061                 return FALSE;
1062         }
1063         memset(flush_buffer, 0x0, sizeof(flush_info));
1064
1065         ret = media_packet_get_tbm_surface(packet, &src_tbm_surf);
1066         if (ret != MEDIA_PACKET_ERROR_NONE || !src_tbm_surf) {
1067                 LOGW("get_tbm_surface is failed");
1068                 goto ERROR;
1069         }
1070
1071         /* get src buffer info */
1072         if (tbm_surface_map(src_tbm_surf, TBM_OPTION_READ|TBM_OPTION_WRITE, &src_info)) {
1073                 LOGW("[src] map is failed");
1074                 goto ERROR;
1075         }
1076
1077         /* create tbm surface */
1078         flush_buffer->tbm_surf = tbm_surface_create(evas_info->w, evas_info->h, src_info.format);
1079
1080         if (!flush_buffer->tbm_surf) {
1081                 LOGE("tbm_surf is NULL!!");
1082                 if (tbm_surface_unmap(src_tbm_surf))
1083                         LOGW("[src] unmap is failed");
1084                 goto ERROR;
1085         }
1086
1087         /* get dst buffer info */
1088         if (tbm_surface_map(flush_buffer->tbm_surf, TBM_OPTION_READ|TBM_OPTION_WRITE, &dst_info)) {
1089                 LOGW("[dst] map is failed");
1090                 if (tbm_surface_unmap(src_tbm_surf))
1091                         LOGW("[src] unmap is failed");
1092                 goto ERROR;
1093         }
1094
1095         if (src_info.size > dst_info.size) {
1096                 LOGE("src size(%d), dst size(%d)!!!", src_info.size, dst_info.size);
1097                 if (tbm_surface_unmap(src_tbm_surf))
1098                         LOGW("[src] unmap is failed");
1099                 if (tbm_surface_unmap(flush_buffer->tbm_surf))
1100                         LOGW("[dst] unmap is failed");
1101                 goto ERROR;
1102         }
1103
1104         /* copy buffer */
1105         switch (src_info.format) {
1106         case TBM_FORMAT_YUV420:
1107                 memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].size);
1108                 memcpy(dst_info.planes[1].ptr, src_info.planes[1].ptr, src_info.planes[1].size);
1109                 memcpy(dst_info.planes[2].ptr, src_info.planes[2].ptr, src_info.planes[2].size);
1110                 break;
1111         case TBM_FORMAT_NV12:
1112                 memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].stride * src_info.height);
1113                 memcpy(dst_info.planes[1].ptr, src_info.planes[1].ptr, src_info.planes[0].stride * src_info.height / 2);
1114                 break;
1115         case TBM_FORMAT_YUYV:
1116                 memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].size);
1117                 break;
1118         default:
1119                 LOGW("unsupported format");
1120                 break;
1121         }
1122
1123 #ifdef _INTERNAL_DEBUG_
1124         __dump_surf(flush_buffer->tbm_surf);
1125         g_cnt_out++;
1126         LOGD("flush_buffer dump is done");
1127 #endif
1128
1129         if (tbm_surface_unmap(src_tbm_surf))
1130                 LOGW("[src] unmap is failed");
1131         if (tbm_surface_unmap(flush_buffer->tbm_surf))
1132                 LOGW("[dst] unmap is failed");
1133
1134         LOGW("copy is done. tbm surface : %p", flush_buffer->tbm_surf);
1135         evas_info->flush_buffer = flush_buffer;
1136
1137         MMER_FLEAVE();
1138
1139         return MM_ERROR_NONE;
1140
1141 ERROR:
1142         if (flush_buffer) {
1143                 if (flush_buffer->tbm_surf) {
1144                         tbm_surface_destroy(flush_buffer->tbm_surf);
1145                         flush_buffer->tbm_surf = NULL;
1146                 }
1147
1148                 free(flush_buffer);
1149                 flush_buffer = NULL;
1150         }
1151         return MM_ERROR_EVASRENDER_INTERNAL;
1152 }
1153
1154 /* release flush buffer */
1155 static void _mm_evas_renderer_release_flush_buffer(mm_evas_info *evas_info)
1156 {
1157         MMER_FENTER();
1158
1159         MMEVAS_RETURN_IF_FAIL(evas_info);
1160
1161         LOGW("release FLUSH BUFFER start");
1162         if (evas_info->flush_buffer->bo)
1163                 evas_info->flush_buffer->bo = NULL;
1164
1165         if (evas_info->flush_buffer->tbm_surf) {
1166                 tbm_surface_destroy(evas_info->flush_buffer->tbm_surf);
1167                 evas_info->flush_buffer->tbm_surf = NULL;
1168         }
1169
1170         LOGW("release FLUSH BUFFER done");
1171
1172         free(evas_info->flush_buffer);
1173         evas_info->flush_buffer = NULL;
1174
1175         MMER_FLEAVE();
1176
1177         return;
1178 }
1179
1180 static void _mm_evas_renderer_get_video_angle(mm_evas_info *evas_info, int *rotate_angle, int *orientation)
1181 {
1182         int rotate = 0;
1183         media_packet_h packet = NULL;
1184         media_packet_rotate_method_e org_orient = 0;
1185
1186         MMER_FENTER();
1187
1188         MMEVAS_RETURN_IF_FAIL(evas_info);
1189         MMEVAS_RETURN_IF_FAIL(rotate_angle);
1190         MMEVAS_RETURN_IF_FAIL(orientation);
1191
1192         rotate = evas_info->rotate;
1193         LOGD("current rotate value: %d", rotate);
1194
1195         /* Counter clockwise */
1196         switch (rotate) {
1197         case EVAS_IMAGE_ORIENT_0: //0
1198                 *rotate_angle = 0;
1199                 break;
1200         case EVAS_IMAGE_ORIENT_90: //1
1201                 *rotate_angle = 90;
1202                 break;
1203         case EVAS_IMAGE_ORIENT_180: //2
1204                 *rotate_angle = 180;
1205                 break;
1206         case EVAS_IMAGE_ORIENT_270: //3
1207                 *rotate_angle = 270;
1208                 break;
1209         default:
1210                 LOGW("wrong angle type : %d", rotate);
1211                 break;
1212         }
1213         LOGD("check display angle: %d", *rotate_angle);
1214
1215         /* get content orientation */
1216         packet = evas_info->pkt_info[evas_info->cur_idx].packet;
1217         MMEVAS_RETURN_IF_FAIL(packet);
1218
1219         media_packet_get_rotate_method(packet, &org_orient);
1220         LOGE("get content orientation : %d", org_orient);
1221
1222         /* Counter clockwise */
1223         switch (org_orient) {
1224         case MEDIA_PACKET_ROTATE_IDENTITY: //0
1225                 *orientation = 0;
1226                 break;
1227         case MEDIA_PACKET_ROTATE_90: //1
1228                 *orientation = 90;
1229                 break;
1230         case MEDIA_PACKET_ROTATE_180: //2
1231                 *orientation = 180;
1232                 break;
1233         case MEDIA_PACKET_ROTATE_270: //3
1234                 *orientation = 270;
1235                 break;
1236         default:
1237                 LOGW("wrong angle type : %d", org_orient);
1238                 break;
1239         }
1240         LOGD("check orientation: %d", *orientation);
1241
1242         return;
1243 }
1244
1245 static void _mm_evas_renderer_update_rotate_angle(mm_evas_info *evas_info)
1246 {
1247
1248         int required_angle = 0; /* Angle required for straight view */
1249         int rotate_angle = 0;
1250         int orientation = 0;
1251
1252         MMER_FENTER();
1253
1254         MMEVAS_RETURN_IF_FAIL(evas_info);
1255
1256         _mm_evas_renderer_get_video_angle(evas_info, &rotate_angle, &orientation);
1257
1258         required_angle = 360 - orientation;
1259         rotate_angle = (rotate_angle + required_angle) % 360;
1260
1261         /* chech if supported or not */
1262         if (rotate_angle % 90) {
1263                 LOGD("not supported rotation angle = %d", rotate_angle);
1264                 return;
1265         }
1266
1267         switch (rotate_angle) {
1268         case 0:
1269                 evas_info->rotate_angle = EVAS_IMAGE_ORIENT_0;
1270                 break;
1271         case 90:
1272                 evas_info->rotate_angle = EVAS_IMAGE_ORIENT_90;
1273                 break;
1274         case 180:
1275                 evas_info->rotate_angle = EVAS_IMAGE_ORIENT_180;
1276                 break;
1277         case 270:
1278                 evas_info->rotate_angle = EVAS_IMAGE_ORIENT_270;
1279                 break;
1280         }
1281
1282         LOGD("setting rotation angle : %d", evas_info->rotate_angle);
1283
1284         return;
1285 }
1286
1287 void mm_evas_renderer_write(media_packet_h packet, void *data)
1288 {
1289         MMER_FENTER();
1290
1291         mm_evas_info *handle = (mm_evas_info *)data;
1292         int ret = MEDIA_PACKET_ERROR_NONE;
1293         bool has;
1294         tbm_surface_h tbm_surf;
1295         gint new_idx;
1296
1297         MMEVAS_RETURN_IF_FAIL(packet);
1298         LOGD("packet [%p]", packet);
1299
1300         if (!handle) {
1301                 LOGE("handle %p is NULL", handle);
1302                 goto INVALID_HANDLE;
1303         }
1304         g_mutex_lock(&handle->idx_lock);
1305
1306         ret = media_packet_has_tbm_surface_buffer(packet, &has);
1307         if (ret != MEDIA_PACKET_ERROR_NONE) {
1308                 LOGW("has_tbm_surface is failed");
1309                 goto ERROR;
1310         }
1311         /* FIXME: when setCaps occurs, _get_video_size should be called */
1312         /* currently we are always checking it */
1313         if (has && _get_video_size(packet, handle)) {
1314                 /* Attention! if this error occurs, we need to consider managing buffer */
1315                 if (handle->sent_buffer_cnt > 3) {
1316                         LOGE("too many buffers are not released %d", handle->sent_buffer_cnt);
1317                         goto ERROR;
1318                 }
1319                 ret = media_packet_get_tbm_surface(packet, &tbm_surf);
1320                 if (ret != MEDIA_PACKET_ERROR_NONE || !tbm_surf) {
1321                         LOGW("get_tbm_surface is failed");
1322                         goto ERROR;
1323                 }
1324
1325                 /* find new index for current packet */
1326                 new_idx = _find_empty_index(handle);
1327                 if (new_idx == -1)
1328                         goto ERROR;
1329
1330 #ifdef _INTERNAL_DEBUG_
1331                 int ret2 = 0;
1332                 if ((g_cnt_in%10 == 0) && (g_cnt_in < 500))
1333                         ret2 = __dump_pkt(packet, handle->w, handle->h);
1334
1335                 if (ret2)
1336                         LOGW("__dump_pkt() is failed");
1337                 else
1338                         g_cnt_in++;
1339 #endif
1340                 /* save previous index */
1341                 handle->pkt_info[new_idx].prev_idx = handle->cur_idx;
1342                 handle->pkt_info[new_idx].packet = packet;
1343                 handle->pkt_info[new_idx].tbm_surf = tbm_surf;
1344                 handle->cur_idx = new_idx;
1345                 handle->sent_buffer_cnt++;
1346                 LOGD("sent packet %d", handle->sent_buffer_cnt);
1347
1348                 ret = _mm_evas_pipe_write(handle, UPDATE_TBM_SURF);
1349                 if (ret != MM_ERROR_NONE) {
1350                         handle->pkt_info[new_idx].packet = NULL;
1351                         handle->pkt_info[new_idx].tbm_surf = NULL;
1352                         handle->pkt_info[new_idx].prev_idx = -1;
1353                         handle->cur_idx = handle->pkt_info[new_idx].prev_idx;
1354                         handle->sent_buffer_cnt--;
1355                         LOGW("Failed to ecore_pipe_write() for updating tbm surf\n");
1356                         goto ERROR;
1357                 }
1358         } else {
1359                 LOGW("no tbm_surf");
1360                 goto ERROR;
1361         }
1362         g_mutex_unlock(&handle->idx_lock);
1363
1364         MMER_FLEAVE();
1365
1366         return;
1367 ERROR:
1368         g_mutex_unlock(&handle->idx_lock);
1369         /* destroy media_packet immediately */
1370         g_mutex_lock(&handle->mp_lock);
1371         LOGD("can't write. destroy packet [%p]", packet);
1372         if (handle && handle->packet_rendered_cb) {
1373                 handle->packet_rendered_cb(packet, handle->packet_rendered_cb_user);
1374         } else {
1375                 if (media_packet_destroy(packet) != MEDIA_PACKET_ERROR_NONE)
1376                         LOGE("media_packet_destroy failed %p", packet);
1377                 packet = NULL;
1378         }
1379         g_mutex_unlock(&handle->mp_lock);
1380         return;
1381 INVALID_HANDLE:
1382         LOGD("can't write. destroy packet [%p]", packet);
1383         if (media_packet_destroy(packet) != MEDIA_PACKET_ERROR_NONE)
1384                 LOGE("media_packet_destroy failed %p", packet);
1385         packet = NULL;
1386         return;
1387 }
1388
1389 int mm_evas_renderer_create(MMHandleType *handle, Evas_Object *eo)
1390 {
1391         int ret = MM_ERROR_NONE;
1392         mm_evas_info *evas_info = NULL;
1393
1394         MMER_FENTER();
1395
1396         MMEVAS_RETURN_VAL_IF_FAIL(handle, MM_ERROR_EVASRENDER_INVALID_ARGUMENT);
1397         MMEVAS_RETURN_VAL_IF_FAIL(eo, MM_ERROR_EVASRENDER_INVALID_ARGUMENT);
1398
1399         ret = _mm_evas_renderer_create(&evas_info);
1400         if (ret != MM_ERROR_NONE) {
1401                 LOGE("fail to create evas_info");
1402                 return ret;
1403         }
1404         ret = _mm_evas_renderer_set_info(evas_info, eo);
1405         if (ret != MM_ERROR_NONE) {
1406                 LOGE("fail to init evas_info");
1407                 if (_mm_evas_renderer_destroy(&evas_info) != MM_ERROR_NONE)
1408                         LOGE("fail to destroy evas_info");
1409                 return ret;
1410         }
1411
1412         *handle = (MMHandleType)evas_info;
1413
1414         return MM_ERROR_NONE;
1415 }
1416
1417 int mm_evas_renderer_destroy(MMHandleType *handle)
1418 {
1419         int ret = MM_ERROR_NONE;
1420         mm_evas_info *evas_info = (mm_evas_info *)*handle;
1421
1422         MMER_FENTER();
1423
1424         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1425
1426         ret = _mm_evas_renderer_destroy(&evas_info);
1427         if (ret != MM_ERROR_NONE) {
1428                 LOGE("fail to destroy evas_info");
1429                 return ret;
1430         }
1431         *handle = NULL;
1432
1433         MMER_FLEAVE();
1434
1435         return MM_ERROR_NONE;
1436 }
1437
1438 int mm_evas_renderer_set_visible(MMHandleType handle, bool visible)
1439 {
1440         int ret = MM_ERROR_NONE;
1441         mm_evas_info *evas_info = (mm_evas_info *)handle;
1442
1443         MMER_FENTER();
1444
1445         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1446
1447         if (evas_info->visible != visible) {
1448                 evas_info->visible = visible;
1449                 ret = _mm_evas_pipe_write(evas_info, UPDATE_VISIBILITY);
1450         }
1451
1452         MMER_FLEAVE();
1453
1454         return ret;
1455 }
1456
1457 int mm_evas_renderer_get_visible(MMHandleType handle, bool *visible)
1458 {
1459         mm_evas_info *evas_info = (mm_evas_info *)handle;
1460
1461         MMER_FENTER();
1462
1463         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1464
1465         *visible = evas_info->visible;
1466
1467         MMER_FLEAVE();
1468
1469         return MM_ERROR_NONE;
1470 }
1471
1472 int mm_evas_renderer_set_rotation(MMHandleType handle, int rotate)
1473 {
1474         int ret = MM_ERROR_NONE;
1475         mm_evas_info *evas_info = (mm_evas_info *)handle;
1476         gint value;
1477
1478         MMER_FENTER();
1479
1480         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1481
1482         switch (rotate) {
1483         case DEGREE_0:
1484                 value = EVAS_IMAGE_ORIENT_0;
1485                 break;
1486         case DEGREE_90:
1487                 value = EVAS_IMAGE_ORIENT_90;
1488                 break;
1489         case DEGREE_180:
1490                 value = EVAS_IMAGE_ORIENT_180;
1491                 break;
1492         case DEGREE_270:
1493                 value = EVAS_IMAGE_ORIENT_270;
1494                 break;
1495         default:
1496                 return MM_ERROR_EVASRENDER_INVALID_ARGUMENT;
1497         }
1498
1499         if (evas_info->rotate != value) {
1500                 evas_info->update_needed = TRUE;
1501                 evas_info->rotate = value;
1502                 evas_info->rendering_info_changed = TRUE;
1503
1504                 ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF);
1505         }
1506
1507         MMER_FLEAVE();
1508
1509         return ret;
1510 }
1511
1512 int mm_evas_renderer_get_rotation(MMHandleType handle, int *rotate)
1513 {
1514         mm_evas_info *evas_info = (mm_evas_info *)handle;
1515
1516         MMER_FENTER();
1517
1518         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1519
1520         switch (evas_info->rotate) {
1521         case EVAS_IMAGE_ORIENT_0:
1522                 *rotate = DEGREE_0;
1523                 break;
1524         case EVAS_IMAGE_ORIENT_90:
1525                 *rotate = DEGREE_90;
1526                 break;
1527         case EVAS_IMAGE_ORIENT_180:
1528                 *rotate = DEGREE_180;
1529                 break;
1530         case EVAS_IMAGE_ORIENT_270:
1531                 *rotate = DEGREE_270;
1532                 break;
1533         default:
1534                 return MM_ERROR_EVASRENDER_INVALID_ARGUMENT;
1535         }
1536
1537         MMER_FLEAVE();
1538
1539         return MM_ERROR_NONE;
1540 }
1541
1542 int mm_evas_renderer_set_geometry(MMHandleType handle, int mode)
1543 {
1544         int ret = MM_ERROR_NONE;
1545         mm_evas_info *evas_info = (mm_evas_info *)handle;
1546
1547         MMER_FENTER();
1548
1549         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1550         MMEVAS_RETURN_VAL_IF_FAIL(mode >= DISP_GEO_METHOD_LETTER_BOX && mode < DISP_GEO_METHOD_NUM, MM_ERROR_EVASRENDER_INVALID_ARGUMENT);
1551
1552         if (evas_info->display_geometry_method != mode) {
1553                 evas_info->update_needed = TRUE;
1554                 evas_info->pre_display_geometry_method = evas_info->display_geometry_method;
1555                 evas_info->display_geometry_method = mode;
1556                 evas_info->rendering_info_changed = TRUE;
1557
1558                 /* ecore_pipe_write is needed, because of setting ratio for letterbox mode */
1559                 ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF);
1560         }
1561
1562         MMER_FLEAVE();
1563
1564         return ret;
1565 }
1566
1567 int mm_evas_renderer_get_geometry(MMHandleType handle, int *mode)
1568 {
1569         mm_evas_info *evas_info = (mm_evas_info *)handle;
1570
1571         MMER_FENTER();
1572
1573         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1574
1575         *mode = evas_info->display_geometry_method;
1576
1577         MMER_FLEAVE();
1578
1579         return MM_ERROR_NONE;
1580 }
1581
1582 int mm_evas_renderer_set_roi_area(MMHandleType handle, int x, int y, int w, int h)
1583 {
1584         int ret = MM_ERROR_NONE;
1585         mm_evas_info *evas_info = (mm_evas_info *)handle;
1586
1587         MMER_FENTER();
1588
1589         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1590
1591         if (w <= 0 || h <= 0) {
1592                 LOGE("invalid resolution w(%d), h(%d)", w, h);
1593                 return MM_ERROR_EVASRENDER_INVALID_ARGUMENT;
1594         }
1595
1596         if (evas_info->dst_roi.x != x || evas_info->dst_roi.y != y
1597                 || evas_info->dst_roi.w != w || evas_info->dst_roi.h != h) {
1598                 evas_info->dst_roi.x = x;
1599                 evas_info->dst_roi.y = y;
1600                 evas_info->dst_roi.w = w;
1601                 evas_info->dst_roi.h = h;
1602                 evas_info->update_needed = TRUE;
1603                 evas_info->is_set_roi_area = TRUE;
1604                 evas_info->rendering_info_changed = TRUE;
1605
1606                 /* pipe_write could be needed because ratio can be changed on pause state */
1607                 ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF);
1608         }
1609
1610         MMER_FLEAVE();
1611
1612         return ret;
1613 }
1614
1615 int mm_evas_renderer_get_roi_area(MMHandleType handle, int *x, int *y, int *w, int *h)
1616 {
1617         mm_evas_info *evas_info = (mm_evas_info *)handle;
1618
1619         MMER_FENTER();
1620
1621         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1622
1623         *x = evas_info->dst_roi.x;
1624         *y = evas_info->dst_roi.y;
1625         *w = evas_info->dst_roi.w;
1626         *h = evas_info->dst_roi.h;
1627
1628         MMER_FLEAVE();
1629
1630         return MM_ERROR_NONE;
1631 }
1632
1633 int mm_evas_renderer_set_flip(MMHandleType handle, int flip)
1634 {
1635         int ret = MM_ERROR_NONE;
1636         mm_evas_info *evas_info = (mm_evas_info *)handle;
1637         gint value;
1638
1639         MMER_FENTER();
1640
1641         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1642
1643         switch (flip) {
1644         case FLIP_NONE:
1645                 value = EVAS_IMAGE_ORIENT_NONE;
1646                 break;
1647         case FLIP_HORIZONTAL:
1648                 value = EVAS_IMAGE_FLIP_HORIZONTAL;
1649                 break;
1650         case FLIP_VERTICAL:
1651                 value = EVAS_IMAGE_FLIP_VERTICAL;
1652                 break;
1653         case FLIP_BOTH:
1654                 value = EVAS_IMAGE_ORIENT_180;
1655                 break;
1656         default:
1657                 return MM_ERROR_EVASRENDER_INVALID_ARGUMENT;
1658         }
1659
1660         if (evas_info->flip != value) {
1661                 evas_info->update_needed = TRUE;
1662                 evas_info->flip = value;
1663         }
1664
1665         ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF);
1666
1667         MMER_FLEAVE();
1668
1669         return ret;
1670 }
1671
1672 int mm_evas_renderer_get_flip(MMHandleType handle, int *flip)
1673 {
1674         mm_evas_info *evas_info = (mm_evas_info *)handle;
1675
1676         MMER_FENTER();
1677
1678         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1679
1680         switch (evas_info->flip) {
1681         case EVAS_IMAGE_ORIENT_NONE:
1682                 *flip = FLIP_NONE;
1683                 break;
1684         case EVAS_IMAGE_FLIP_HORIZONTAL:
1685                 *flip = FLIP_HORIZONTAL;
1686                 break;
1687         case EVAS_IMAGE_FLIP_VERTICAL:
1688                 *flip = FLIP_VERTICAL;
1689                 break;
1690         case EVAS_IMAGE_ORIENT_180:
1691                 *flip = FLIP_BOTH;
1692                 break;
1693         default:
1694                 return MM_ERROR_EVASRENDER_INVALID_ARGUMENT;
1695         }
1696
1697         MMER_FLEAVE();
1698
1699         return MM_ERROR_NONE;
1700 }
1701
1702 int mm_evas_renderer_retrieve_all_packets(MMHandleType handle, bool keep_screen)
1703 {
1704         int ret = MM_ERROR_NONE;
1705         mm_evas_info *evas_info = (mm_evas_info*) handle;
1706
1707         MMER_FENTER();
1708
1709         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1710
1711         ret = _mm_evas_renderer_retrieve_all_packets(evas_info, keep_screen);
1712
1713         MMER_FLEAVE();
1714
1715         return ret;
1716 }
1717
1718 int mm_evas_renderer_set_packet_rendered_callback(MMHandleType handle, mm_evas_renderer_media_packet_rendered_cb callback, void *user_data)
1719 {
1720         mm_evas_info *evas_info = (mm_evas_info*) handle;
1721
1722         MMER_FENTER();
1723
1724         MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED);
1725
1726         evas_info->packet_rendered_cb = callback;
1727         evas_info->packet_rendered_cb_user = user_data;
1728
1729         LOGW("set rendered callback %p, user_data %p", evas_info->packet_rendered_cb, evas_info->packet_rendered_cb_user);
1730
1731         MMER_FLEAVE();
1732
1733         return MM_ERROR_NONE;
1734 }