/* * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "mm_evas_renderer_private.h" #ifdef LOG_TAG #undef LOG_TAG #endif #define LOG_TAG "MM_EVAS_RENDER" //#define _INTERNAL_DEBUG_ /* debug only */ #define SWAP(a, b) ({int t; t = a; a = b; b = t; }) #define INIT_IDX -1 #define SIGNAL_TIMEOUT 1 #define MMER_FENTER(); LOGD(""); #define MMER_FLEAVE(); LOGD(""); #define MMEVAS_RETURN_IF_FAIL(expr) \ do { \ if (!(expr)) { \ LOGW("faild [%s]", #expr); \ return; \ } \ } while (0) #define MMEVAS_RETURN_VAL_IF_FAIL(expr, var) \ do { \ if (!(expr)) { \ LOGW("faild [%s]", #expr); \ return (var); \ } \ } while (0) enum { DISP_GEO_METHOD_LETTER_BOX = 0, DISP_GEO_METHOD_ORIGIN_SIZE, DISP_GEO_METHOD_FULL_SCREEN, DISP_GEO_METHOD_CROPPED_FULL_SCREEN, DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX, DISP_GEO_METHOD_CUSTOM_ROI, DISP_GEO_METHOD_NUM, }; enum { DEGREE_0 = 0, DEGREE_90, DEGREE_180, DEGREE_270, DEGREE_NUM, }; enum { FLIP_NONE = 0, FLIP_HORIZONTAL, FLIP_VERTICAL, FLIP_BOTH, FLIP_NUM, }; #ifdef _INTERNAL_DEBUG_ static int g_cnt_in = 0; static int g_cnt_out = 0; static int __dump_pkt(media_packet_h pkt, int width, int height); static int __dump_surf(tbm_surface_h tbm_surf); #endif /* internal */ static void _free_previous_packets(mm_evas_info *evas_info); static int _flush_all_packets(mm_evas_info *evas_info); static int _mm_evas_renderer_create(mm_evas_info **evas_info); static int _mm_evas_renderer_destroy(mm_evas_info **evas_info); static int _mm_evas_renderer_set_info(mm_evas_info *evas_info, Evas_Object *eo); static int _mm_evas_renderer_reset(mm_evas_info *evas_info, gboolean is_sub_thread); static void _mm_evas_renderer_update_geometry(mm_evas_info *evas_info); static int _mm_evas_renderer_retrieve_all_packets(mm_evas_info *evas_info, bool keep_screen); static int _mm_evas_renderer_make_flush_buffer(mm_evas_info *evas_info); static void _mm_evas_renderer_release_flush_buffer(mm_evas_info *evas_info); static void _mm_evas_renderer_get_video_angle(mm_evas_info *evas_info, int *rotate_angle, int *orientation); static void _mm_evas_renderer_update_rotate_angle(mm_evas_info *evas_info); static void _mm_evas_renderer_set_callback(mm_evas_info *evas_info); static void _mm_evas_renderer_unset_callback(mm_evas_info *evas_info); static void _mm_evas_renderer_set_evas_object_size(mm_evas_info *evas_info); static gboolean _check_rendering_packet(mm_evas_info *evas_info); /* must be called after the null surface has been set. */ static int _mm_evas_renderer_update_rendering_info(mm_evas_info *evas_info) { MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); MMEVAS_RETURN_VAL_IF_FAIL(evas_info->eo, MM_ERROR_EVASRENDER_NOT_INITIALIZED); 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); if (!evas_info->eo_size.w || !evas_info->eo_size.h) { LOGE("there is no information for evas object size"); return MM_ERROR_EVASRENDER_INTERNAL; } if (!evas_info->w || !evas_info->h) { LOGE("there is no video size from mm_evas_renderer_write() which is callback_func of player or camera"); return MM_ERROR_EVASRENDER_INTERNAL; } _mm_evas_renderer_update_geometry(evas_info); if (!evas_info->result.w || !evas_info->result.h) { LOGE("no information about geometry (%d, %d)", evas_info->result.w, evas_info->result.h); return MM_ERROR_EVASRENDER_INTERNAL; } if (evas_info->video_size_changed) { _mm_evas_renderer_set_evas_object_size(evas_info); evas_info->video_size_changed = FALSE; } if (evas_info->result.x || evas_info->result.y) LOGD("coordinate x, y (%d, %d) for locating video to center", evas_info->result.x, evas_info->result.y); evas_object_image_fill_set(evas_info->eo, evas_info->result.x, evas_info->result.y, evas_info->result.w, evas_info->result.h); MMER_FLEAVE(); return MM_ERROR_NONE; } static void _evas_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) { /* now evas object size is changed */ mm_evas_info *evas_info = data; MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); MMEVAS_RETURN_IF_FAIL(evas_info->eo); g_mutex_lock(&evas_info->idx_lock); if (!_check_rendering_packet(evas_info)) { g_mutex_unlock(&evas_info->idx_lock); return; } g_mutex_unlock(&evas_info->idx_lock); if (_mm_evas_renderer_update_rendering_info(evas_info) == MM_ERROR_NONE) { Evas_Native_Surface *surf; surf = evas_object_image_native_surface_get(evas_info->eo); if (surf) { LOGD("native surface exists"); surf->data.tbm.rot = evas_info->rotate_angle; surf->data.tbm.flip = evas_info->flip; surf->data.tbm.ratio = evas_info->ratio; /* surface set must be called by main thread */ evas_object_image_native_surface_set(evas_info->eo, surf); } else LOGW("there is no surf"); } MMER_FLEAVE(); } static gboolean _check_rendering_packet(mm_evas_info *evas_info) { gint cur_idx = 0; tbm_format tbm_fmt = 0; gchar *s_fmt = NULL; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, FALSE); cur_idx = evas_info->cur_idx; if ((cur_idx == -1) || !evas_info->pkt_info[cur_idx].tbm_surf) { LOGW("cur_idx %d, tbm_surf may be NULL", cur_idx); return FALSE; } if (!evas_info->pkt_info[cur_idx].packet) { LOGE(" Packet is NULL"); return FALSE; } tbm_fmt = tbm_surface_get_format(evas_info->pkt_info[cur_idx].tbm_surf); switch (tbm_fmt) { case TBM_FORMAT_NV12: s_fmt = "TBM_FORMAT_NV12"; break; case TBM_FORMAT_YUV420: s_fmt = "TBM_FORMAT_YUV420"; break; default: s_fmt = "unknown"; break; } LOGD("received idx(%d), packet(%p), format([%d]: %s)", cur_idx, evas_info->pkt_info[cur_idx].packet, tbm_fmt, s_fmt); MMER_FLEAVE(); return TRUE; } /* must be called after the null surface has been set. */ static void _mm_evas_renderer_surface_set(mm_evas_info *evas_info) { gint cur_idx = 0; gint prev_idx = 0; MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); MMEVAS_RETURN_IF_FAIL(evas_info->eo); g_mutex_lock(&evas_info->idx_lock); if (!_check_rendering_packet(evas_info)) { g_mutex_unlock(&evas_info->idx_lock); return; } if (evas_info->rendering_info_changed) { LOGD("Rendering info changed"); if (_mm_evas_renderer_update_rendering_info(evas_info) != MM_ERROR_NONE) goto ERROR; evas_info->rendering_info_changed = FALSE; } 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); if (evas_info->update_needed) { evas_object_image_native_surface_set(evas_info->eo, NULL); evas_info->update_needed = FALSE; } cur_idx = evas_info->cur_idx; prev_idx = evas_info->pkt_info[cur_idx].prev_idx; /* set surface */ Evas_Native_Surface surf = { 0 }; surf.type = EVAS_NATIVE_SURFACE_TBM; surf.version = EVAS_NATIVE_SURFACE_VERSION; surf.data.tbm.buffer = evas_info->pkt_info[cur_idx].tbm_surf; surf.data.tbm.rot = evas_info->rotate_angle; surf.data.tbm.flip = evas_info->flip; surf.data.tbm.ratio = evas_info->ratio; #ifdef _INTERNAL_DEBUG_ int ret2 = 0; if ((g_cnt_out%5 == 0) && (g_cnt_out < 500)) ret2 = __dump_surf(evas_info->pkt_info[cur_idx].tbm_surf); if (ret2) LOGW("__dump_surf() is failed"); else g_cnt_out++; #endif if (evas_info->visible) { /* surface set must be called by main thread */ evas_object_image_native_surface_set(evas_info->eo, &surf); evas_object_image_pixels_dirty_set(evas_info->eo, EINA_TRUE); LOGD("native surface set finish"); } else { LOGD("skip... surface set"); } /* when _evas_pipe_cb is called sequentially, previous packet and current packet will be the same */ if ((prev_idx != -1) && evas_info->pkt_info[prev_idx].packet && (prev_idx != cur_idx)) _free_previous_packets(evas_info); g_mutex_unlock(&evas_info->idx_lock); MMER_FLEAVE(); return; ERROR: if ((prev_idx != -1) && evas_info->pkt_info[prev_idx].packet) { LOGI("cant render"); _free_previous_packets(evas_info); } g_mutex_unlock(&evas_info->idx_lock); return; } /* must be called after the null surface has been set. */ static void _mm_evas_renderer_select_task(mm_evas_info *evas_info, update_info info) { MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); MMEVAS_RETURN_IF_FAIL(evas_info->eo); LOGD("evas_info : %p, info type : %d, evas_info->eo : %p", evas_info, info, evas_info->eo); switch (info) { case UPDATE_VISIBILITY: if (!evas_info->visible) { /* surface set must be called by main thread */ evas_object_image_native_surface_set(evas_info->eo, NULL); evas_object_hide(evas_info->eo); LOGI("object hide.."); LOGD("[LEAVE]"); } else { evas_object_show(evas_info->eo); LOGI("object show.. %d", evas_info->visible); /* video rendering */ _mm_evas_renderer_surface_set(evas_info); } break; case UPDATE_TBM_SURF: /* video rendering */ _mm_evas_renderer_surface_set(evas_info); break; case UPDATE_FLUSH_BUFFER: if (_flush_all_packets(evas_info) != MM_ERROR_NONE) LOGE("flushing packets is failed"); break; default: LOGW("invalid info type : %d", info); break; } MMER_FLEAVE(); return; } static void _evas_pipe_cb(void *data, void *buffer, update_info info) { mm_evas_info *evas_info = data; MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); MMEVAS_RETURN_IF_FAIL(evas_info->eo); LOGD("ecore_pipe is called"); if (!evas_info->is_set_resize_cb) _mm_evas_renderer_set_callback(evas_info); g_mutex_lock(&evas_info->mp_lock); _mm_evas_renderer_select_task(evas_info, info); g_mutex_unlock(&evas_info->mp_lock); MMER_FLEAVE(); return; } #ifdef _INTERNAL_DEBUG_ static int __dump_pkt(media_packet_h pkt, int width, int height) { uint8_t *data; uint64_t size; char filename[128] = {0}; FILE *fp = NULL; int i = 0; int stride_width, stride_height; uint32_t plane_num = 0; sprintf(filename, "/tmp/DUMP_IN_IMG_%2.2d.dump", g_cnt_in); fp = fopen(filename, "wb"); if (fp == NULL) return 1; media_packet_get_number_of_video_planes(pkt, &plane_num); /* temporary expedient to decide format */ media_packet_get_video_plane_data_ptr(pkt, 0, (void **)&data); media_packet_get_video_stride_width(pkt, 0, &stride_width); media_packet_get_video_stride_height(pkt, 0, &stride_height); media_packet_get_buffer_size(pkt, &size); LOGI("[0]stride : %d, %d", stride_width, stride_height); for (i = 0; i < height; i++) { fwrite(data, width, 1, fp); data += stride_width; } if (plane_num == 2) { /* hw codec(NV12) */ media_packet_get_video_plane_data_ptr(pkt, 1, (void **)&data); media_packet_get_video_stride_width(pkt, 1, &stride_width); for (i = 0; i < height/2; i++) { fwrite(data, width, 1, fp); data += stride_width; } } else if (plane_num == 3) { /* sw codec(YUV420) */ media_packet_get_video_plane_data_ptr(pkt, 1, (void **)&data); media_packet_get_video_stride_width(pkt, 1, &stride_width); for (i = 0; i < height/2; i++) { fwrite(data, width/2, 1, fp); data += stride_width; } LOGI("[1]stride : %d, %d", stride_width, stride_height); media_packet_get_video_plane_data_ptr(pkt, 2, (void **)&data); media_packet_get_video_stride_width(pkt, 2, &stride_width); for (i = 0; i < height/2; i++) { fwrite(data, width/2, 1, fp); data += stride_width; } LOGI("[2]stride : %d, %d", stride_width, stride_height); } else { LOGW("plane_num %d", plane_num); fclose(fp); return 1; } LOGI("DUMP_IN_IMG_%2.2d : buffer size(%d) data(%p)", g_cnt_in, (int)size, data); fclose(fp); return 0; } static int __dump_surf(tbm_surface_h tbm_surf) { char filename[128] = {0}; tbm_surface_info_s info = {0}; sprintf(filename, "DUMP_OUT_IMG_%2.2d", g_cnt_out); if (tbm_surface_get_info(tbm_surf, &info)) { LOGE("get_info is failed"); return 1; } tbm_surface_internal_dump_start("/tmp", info.width, info.height, 1); tbm_surface_internal_dump_buffer(tbm_surf, filename); tbm_surface_internal_dump_end(); LOGI("[0]stride : %d, offset : %d", (int)info.planes[0].stride, (int)info.planes[0].offset); LOGI("[1]stride : %d, offset : %d", (int)info.planes[1].stride, (int)info.planes[1].offset); LOGI("[2]stride : %d, offset : %d", (int)info.planes[2].stride, (int)info.planes[2].offset); 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); return 0; } #endif static void _free_previous_packets(mm_evas_info *evas_info) { gint index = evas_info->cur_idx; gint prev_idx = evas_info->pkt_info[index].prev_idx; MMER_FENTER(); while (prev_idx != -1) { LOGD("destroy previous packet [%p] idx %d", evas_info->pkt_info[prev_idx].packet, prev_idx); if (evas_info->packet_rendered_cb) { evas_info->packet_rendered_cb(evas_info->pkt_info[prev_idx].packet, evas_info->packet_rendered_cb_user); } else { if (media_packet_destroy(evas_info->pkt_info[prev_idx].packet) != MEDIA_PACKET_ERROR_NONE) LOGE("media_packet_destroy failed %p", evas_info->pkt_info[prev_idx].packet); } evas_info->sent_buffer_cnt--; evas_info->pkt_info[prev_idx].packet = NULL; evas_info->pkt_info[prev_idx].tbm_surf = NULL; evas_info->pkt_info[index].prev_idx = -1; /* move index to previous index */ index = prev_idx; prev_idx = evas_info->pkt_info[prev_idx].prev_idx; LOGD("sent packet %d", evas_info->sent_buffer_cnt); } MMER_FLEAVE(); return; } static int _get_video_size(media_packet_h packet, mm_evas_info *evas_info) { media_format_h fmt; MMER_FENTER(); if (media_packet_get_format(packet, &fmt) == MEDIA_PACKET_ERROR_NONE) { int w, h; if (media_format_get_video_info(fmt, NULL, &w, &h, NULL, NULL) == MEDIA_PACKET_ERROR_NONE) { LOGD("video width = %d, height =%d", w, h); if (w != evas_info->w || h != evas_info->h) { evas_info->w = w; evas_info->h = h; evas_info->rendering_info_changed = TRUE; evas_info->video_size_changed = TRUE; } return true; } else LOGW("media_format_get_video_info is failed"); if (media_format_unref(fmt) != MEDIA_PACKET_ERROR_NONE) /* because of media_packet_get_format */ LOGW("media_format_unref is failed"); } else { LOGW("media_packet_get_format is failed"); } MMER_FLEAVE(); return false; } static int _find_empty_index(mm_evas_info *evas_info) { int i; MMER_FENTER(); for (i = 0; i < MAX_PACKET_NUM; i++) { if (!evas_info->pkt_info[i].packet) { LOGD("selected idx %d", i); return i; } } LOGE("there is no empty idx"); MMER_FLEAVE(); return -1; } /* must be called after the null surface has been set. */ static int _destroy_all_packets(mm_evas_info *evas_info) { int ret = MM_ERROR_NONE; int ret_mp = MEDIA_PACKET_ERROR_NONE; int i = 0; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); g_mutex_lock(&evas_info->idx_lock); for (i = 0; i < MAX_PACKET_NUM; i++) { if (evas_info->pkt_info[i].packet) { /* destroy all packets */ LOGD("destroy packet [%p]", evas_info->pkt_info[i].packet); if (evas_info->packet_rendered_cb) { evas_info->packet_rendered_cb(evas_info->pkt_info[i].packet, evas_info->packet_rendered_cb_user); } else { ret_mp = media_packet_destroy(evas_info->pkt_info[i].packet); if (ret_mp != MEDIA_PACKET_ERROR_NONE) { LOGW("media_packet_destroy failed %p", evas_info->pkt_info[i].packet); ret = MM_ERROR_EVASRENDER_INTERNAL; } } evas_info->sent_buffer_cnt--; evas_info->pkt_info[i].packet = NULL; evas_info->pkt_info[i].tbm_surf = NULL; evas_info->pkt_info[i].prev_idx = INIT_IDX; } } if (evas_info->sent_buffer_cnt != 0) LOGE("it should be 0 --> [%d]", evas_info->sent_buffer_cnt); evas_info->sent_buffer_cnt = 0; evas_info->cur_idx = INIT_IDX; evas_info->flush_all_packets = TRUE; g_mutex_unlock(&evas_info->idx_lock); MMER_FLEAVE(); return ret; } static int _set_flush_buffer(mm_evas_info *evas_info) { int ret = MM_ERROR_NONE; Evas_Native_Surface surf = { 0 }; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); /* set flush buffer surface*/ surf.type = EVAS_NATIVE_SURFACE_TBM; surf.version = EVAS_NATIVE_SURFACE_VERSION; surf.data.tbm.buffer = evas_info->flush_buffer->tbm_surf; surf.data.tbm.rot = evas_info->rotate_angle; surf.data.tbm.flip = evas_info->flip; surf.data.tbm.ratio = evas_info->ratio; /* surface set must be called by main thread */ evas_object_image_native_surface_set(evas_info->eo, &surf); evas_object_image_pixels_dirty_set(evas_info->eo, EINA_TRUE); LOGD("flush_buffer surf(%p), rotate(%d), flip(%d)", evas_info->flush_buffer->tbm_surf, evas_info->rotate_angle, evas_info->flip); return ret; } /* EVAS API must be called by main thread */ static int _flush_all_packets(mm_evas_info *evas_info) { int ret = MM_ERROR_NONE; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); MMEVAS_RETURN_VAL_IF_FAIL(evas_info->eo, MM_ERROR_EVASRENDER_NOT_INITIALIZED); /* update the screen only if visible is true */ /* if flush buffer is null, we cant keep screen */ if (evas_info->keep_screen && evas_info->visible && evas_info->flush_buffer) { /* _set_flush_buffer */ ret = _set_flush_buffer(evas_info); if (ret != MM_ERROR_NONE) return ret; } else { /* unset evas native surface for removing rendered video frame */ evas_object_image_native_surface_set(evas_info->eo, NULL); evas_object_image_pixels_dirty_set(evas_info->eo, EINA_TRUE); _mm_evas_renderer_unset_callback(evas_info); } LOGD("sent packet %d", evas_info->sent_buffer_cnt); ret = _destroy_all_packets(evas_info); if (ret == MM_ERROR_NONE) { g_mutex_lock(&evas_info->evas_lock); LOGD("send signal[COND_RETRIEVE]"); g_cond_signal(&evas_info->evas_cond[COND_RETRIEVE]); g_mutex_unlock(&evas_info->evas_lock); } MMER_FLEAVE(); return ret; } static void _mm_evas_renderer_set_callback(mm_evas_info *evas_info) { MMER_FENTER(); if (evas_info->eo) { LOGD("resize callback add"); evas_object_event_callback_add(evas_info->eo, EVAS_CALLBACK_RESIZE, _evas_resize_cb, evas_info); evas_info->is_set_resize_cb = TRUE; } MMER_FLEAVE(); } static void _mm_evas_renderer_unset_callback(mm_evas_info *evas_info) { MMER_FENTER(); if (evas_info->eo) { LOGD("resize callback del"); evas_object_event_callback_del(evas_info->eo, EVAS_CALLBACK_RESIZE, _evas_resize_cb); evas_info->is_set_resize_cb = FALSE; } MMER_FLEAVE(); } static void _mm_evas_renderer_set_evas_object_size(mm_evas_info *evas_info) { MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); MMEVAS_RETURN_IF_FAIL(evas_info->eo); if (evas_info->w > 0 && evas_info->h > 0) evas_object_image_size_set(evas_info->eo, evas_info->w, evas_info->h); evas_object_size_hint_align_set(evas_info->eo, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(evas_info->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); MMER_FLEAVE(); return; } static int _mm_evas_pipe_write(mm_evas_info *evas_info, update_info info) { int ret = MM_ERROR_NONE; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); MMEVAS_RETURN_VAL_IF_FAIL(evas_info->epipe, MM_ERROR_EVASRENDER_NOT_INITIALIZED); g_mutex_lock(&evas_info->write_lock); if (!ecore_pipe_write(evas_info->epipe, evas_info, info)) { LOGW("fail to ecore_pipe_write() for update info type(%d)", info); ret = MM_ERROR_EVASRENDER_INTERNAL; } g_mutex_unlock(&evas_info->write_lock); MMER_FLEAVE(); return ret; } static int _mm_evas_renderer_create(mm_evas_info **evas_info) { mm_evas_info *ptr = NULL; MMER_FENTER(); ptr = g_malloc0(sizeof(mm_evas_info)); if (!ptr) { LOGE("Cannot allocate memory for evas_info\n"); goto ERROR; } else { *evas_info = ptr; LOGD("Success create evas_info(%p)", *evas_info); } g_mutex_init(&ptr->mp_lock); g_mutex_init(&ptr->idx_lock); g_mutex_init(&ptr->write_lock); g_mutex_init(&ptr->evas_lock); g_cond_init(&ptr->evas_cond[COND_RETRIEVE]); g_cond_init(&ptr->evas_cond[COND_DESTROY]); MMER_FLEAVE(); return MM_ERROR_NONE; ERROR: *evas_info = NULL; return MM_ERROR_EVASRENDER_NO_FREE_SPACE; } static int _mm_evas_renderer_destroy(mm_evas_info **evas_info) { int ret = MM_ERROR_NONE; mm_evas_info *ptr = (mm_evas_info *)*evas_info; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(ptr, MM_ERROR_EVASRENDER_NOT_INITIALIZED); LOGD("finalize evas_info %p", ptr); ret = _mm_evas_renderer_reset(ptr, FALSE); if (ret != MM_ERROR_NONE) LOGE("_mm_evas_renderer_reset is failed"); g_mutex_clear(&ptr->mp_lock); g_mutex_clear(&ptr->idx_lock); g_mutex_clear(&ptr->write_lock); g_mutex_clear(&ptr->evas_lock); g_cond_clear(&ptr->evas_cond[COND_RETRIEVE]); g_cond_clear(&ptr->evas_cond[COND_DESTROY]); g_free(ptr); ptr = NULL; MMER_FLEAVE(); return ret; } static int _mm_evas_renderer_set_info(mm_evas_info *evas_info, Evas_Object *eo) { int i; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); MMEVAS_RETURN_VAL_IF_FAIL(eo, MM_ERROR_EVASRENDER_INVALID_ARGUMENT); g_mutex_lock(&evas_info->idx_lock); LOGD("set evas_info"); for (i = 0; i < MAX_PACKET_NUM; i++) { evas_info->pkt_info[i].packet = NULL; evas_info->pkt_info[i].tbm_surf = NULL; evas_info->pkt_info[i].prev_idx = -1; } evas_info->flush_all_packets = FALSE; evas_info->rendering_info_changed = FALSE; evas_info->video_size_changed = FALSE; evas_info->w = evas_info->h = 0; evas_info->cur_idx = -1; evas_info->dst_roi.x = evas_info->dst_roi.y = evas_info->dst_roi.w = evas_info->dst_roi.h = 0; evas_info->is_set_roi_area = FALSE; evas_info->is_set_resize_cb = FALSE; evas_info->display_geometry_method = evas_info->pre_display_geometry_method = DISP_GEO_METHOD_LETTER_BOX; evas_info->eo = eo; evas_info->epipe = ecore_pipe_add((Ecore_Pipe_Cb) _evas_pipe_cb, evas_info); if (!evas_info->epipe) { LOGE("pipe is not created"); g_mutex_unlock(&evas_info->idx_lock); return MM_ERROR_EVASRENDER_INTERNAL; } LOGD("created pipe %p", evas_info->epipe); 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); 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); g_mutex_unlock(&evas_info->idx_lock); MMER_FLEAVE(); return MM_ERROR_NONE; } static int _mm_evas_renderer_reset(mm_evas_info *evas_info, gboolean is_sub_thread) { int ret = MM_ERROR_NONE; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); MMEVAS_RETURN_VAL_IF_FAIL(evas_info->eo, MM_ERROR_EVASRENDER_NOT_INITIALIZED); g_mutex_lock(&evas_info->mp_lock); evas_info->eo_size.x = evas_info->eo_size.y = evas_info->eo_size.w = evas_info->eo_size.h = 0; evas_info->dst_roi.x = evas_info->dst_roi.y = evas_info->dst_roi.w = evas_info->dst_roi.h = 0; evas_info->w = evas_info->h = 0; if (evas_info->flush_buffer) _mm_evas_renderer_release_flush_buffer(evas_info); if (evas_info->eo) evas_info->eo = NULL; if (evas_info->epipe) { LOGD("pipe %p will be deleted", evas_info->epipe); ecore_pipe_del(evas_info->epipe); evas_info->epipe = NULL; } if (is_sub_thread) { g_mutex_lock(&evas_info->evas_lock); LOGD("send signal[COND_DESTROY]"); g_cond_signal(&evas_info->evas_cond[COND_DESTROY]); g_mutex_unlock(&evas_info->evas_lock); } g_mutex_unlock(&evas_info->mp_lock); MMER_FLEAVE(); return ret; } static void _mm_evas_renderer_update_geometry(mm_evas_info *evas_info) { gint video_width = 0; gint video_height = 0; rect_info result = { 0 }; gint disp_mode = -1; MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); MMEVAS_RETURN_IF_FAIL(evas_info->eo); //need to check evas object /* get rotate angle with content orientaion */ _mm_evas_renderer_update_rotate_angle(evas_info); result.x = 0; result.y = 0; video_width = evas_info->w; video_height = evas_info->h; /* Only SWAP is needed for result coordination calculation */ if (evas_info->rotate_angle == DEGREE_90 || evas_info->rotate_angle == DEGREE_270) { SWAP(video_width, video_height); #ifdef _INTERNAL_DEBUG_ LOGD("swapped width %d, height %d", video_width, video_height); #endif } 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); LOGD("video size (w:%d,h:%d)", video_width, video_height); if (evas_info->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI && evas_info->is_set_roi_area == FALSE) { disp_mode = evas_info->pre_display_geometry_method; LOGD("ROI area isn't set. and use previous display geometry method(%d)", disp_mode); } else { disp_mode = evas_info->display_geometry_method; } switch (disp_mode) { case DISP_GEO_METHOD_LETTER_BOX: /* set black padding for letter box mode */ LOGD("letter box mode"); evas_info->ratio = (float) evas_info->w / evas_info->h; /* need to set original video ratio */ result.w = evas_info->eo_size.w; result.h = evas_info->eo_size.h; break; case DISP_GEO_METHOD_ORIGIN_SIZE: LOGD("origin size mode"); evas_info->ratio = 0; /* set coordinate for each case */ result.x = (evas_info->eo_size.w - video_width) / 2; result.y = (evas_info->eo_size.h - video_height) / 2; result.w = video_width; result.h = video_height; break; case DISP_GEO_METHOD_FULL_SCREEN: LOGD("full screen mode"); evas_info->ratio = 0; result.w = evas_info->eo_size.w; result.h = evas_info->eo_size.h; break; case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: LOGD("cropped full screen mode"); evas_info->ratio = 0; float eo_ratio = (float)evas_info->eo_size.w / evas_info->eo_size.h; float video_ratio = (float)video_width / video_height; /* compare evas object's ratio with video's */ if (eo_ratio > video_ratio) { result.w = evas_info->eo_size.w; result.h = evas_info->eo_size.w * video_height / video_width; result.y = -(result.h - evas_info->eo_size.h) / 2; } else { result.w = evas_info->eo_size.h * video_width / video_height; result.h = evas_info->eo_size.h; result.x = -(result.w - evas_info->eo_size.w) / 2; } break; case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX: /* if video size is smaller than evas object's, it will be set to origin size mode */ if ((evas_info->eo_size.w > video_width) && (evas_info->eo_size.h > video_height)) { LOGD("origin size or letter box mode : set origin size mode"); evas_info->ratio = 0; result.x = (evas_info->eo_size.w - video_width) / 2; result.y = (evas_info->eo_size.h - video_height) / 2; result.w = video_width; result.h = video_height; } else { LOGD("origin size or letter box mode : set letter box mode"); evas_info->ratio = (float) evas_info->w / evas_info->h; /* need to set original video ratio */ result.w = evas_info->eo_size.w; result.h = evas_info->eo_size.h; } break; case DISP_GEO_METHOD_CUSTOM_ROI: LOGD("custom roi mode"); if (evas_info->is_set_roi_area == FALSE) { LOGW("ROI Area isn't set"); return; } /* roi need to set -1 */ evas_info->ratio = -1; result.x = evas_info->dst_roi.x; result.y = evas_info->dst_roi.y; result.w = evas_info->dst_roi.w; result.h = evas_info->dst_roi.h; if (evas_info->rotate_angle == DEGREE_90 || evas_info->rotate_angle == DEGREE_270) SWAP(result.w, result.h); break; default: LOGW("unsupported mode."); break; } evas_info->result.x = result.x; evas_info->result.y = result.y; evas_info->result.w = result.w; evas_info->result.h = result.h; LOGD("geometry result [%d, %d, %d, %d]", evas_info->result.x, evas_info->result.y, evas_info->result.w, evas_info->result.h); MMER_FLEAVE(); } static int _mm_evas_renderer_retrieve_all_packets(mm_evas_info *evas_info, bool keep_screen) { int ret = MM_ERROR_NONE; pid_t pid = getpid(); pid_t tid = syscall(SYS_gettid); gint64 end_time = g_get_monotonic_time() + SIGNAL_TIMEOUT * G_TIME_SPAN_SECOND; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); /* this API can be call by sub thread */ LOGD("pid [%d], tid [%d]", pid, tid); /* make flush buffer */ if (keep_screen) ret = _mm_evas_renderer_make_flush_buffer(evas_info); evas_info->keep_screen = keep_screen; if (pid == tid) { /* API call by main thread */ /* flush all packet */ g_mutex_lock(&evas_info->mp_lock); ret = _flush_all_packets(evas_info); if (ret != MM_ERROR_NONE) LOGE("flushing packets is failed"); g_mutex_unlock(&evas_info->mp_lock); } else { /* flush all packet */ g_mutex_lock(&evas_info->evas_lock); ret = _mm_evas_pipe_write(evas_info, UPDATE_FLUSH_BUFFER); if (ret == MM_ERROR_NONE) { if (!g_cond_wait_until(&evas_info->evas_cond[COND_RETRIEVE], &evas_info->evas_lock, end_time)) { //timeout LOGW("timeout: main thread is busy, App need to handle main thread well."); } } g_mutex_unlock(&evas_info->evas_lock); } MMER_FLEAVE(); return ret; } /* make buffer for copying */ static int _mm_evas_renderer_make_flush_buffer(mm_evas_info *evas_info) { MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); if (evas_info->cur_idx == -1) { /* it is deemed ERROR_NONE, because this API is used only for retrieving buffers */ LOGW("there is no remaining buffer"); return MM_ERROR_NONE; } media_packet_h packet = evas_info->pkt_info[evas_info->cur_idx].packet; MMEVAS_RETURN_VAL_IF_FAIL(packet, MM_ERROR_EVASRENDER_INTERNAL); flush_info *flush_buffer = NULL; tbm_surface_h src_tbm_surf = NULL; tbm_surface_info_s src_info = {0}; tbm_surface_info_s dst_info = {0}; int ret = MM_ERROR_NONE; if (evas_info->flush_buffer) _mm_evas_renderer_release_flush_buffer(evas_info); /* malloc buffer */ flush_buffer = (flush_info *)malloc(sizeof(flush_info)); if (flush_buffer == NULL) { LOGE("malloc is failed"); return FALSE; } memset(flush_buffer, 0x0, sizeof(flush_info)); ret = media_packet_get_tbm_surface(packet, &src_tbm_surf); if (ret != MEDIA_PACKET_ERROR_NONE || !src_tbm_surf) { LOGW("get_tbm_surface is failed"); goto ERROR; } /* get src buffer info */ if (tbm_surface_map(src_tbm_surf, TBM_OPTION_READ|TBM_OPTION_WRITE, &src_info)) { LOGW("[src] map is failed"); goto ERROR; } /* create tbm surface */ flush_buffer->tbm_surf = tbm_surface_create(evas_info->w, evas_info->h, src_info.format); if (!flush_buffer->tbm_surf) { LOGE("tbm_surf is NULL!!"); if (tbm_surface_unmap(src_tbm_surf)) LOGW("[src] unmap is failed"); goto ERROR; } /* get dst buffer info */ if (tbm_surface_map(flush_buffer->tbm_surf, TBM_OPTION_READ|TBM_OPTION_WRITE, &dst_info)) { LOGW("[dst] map is failed"); if (tbm_surface_unmap(src_tbm_surf)) LOGW("[src] unmap is failed"); goto ERROR; } if (src_info.size > dst_info.size) { LOGE("src size(%d), dst size(%d)!!!", src_info.size, dst_info.size); if (tbm_surface_unmap(src_tbm_surf)) LOGW("[src] unmap is failed"); if (tbm_surface_unmap(flush_buffer->tbm_surf)) LOGW("[dst] unmap is failed"); goto ERROR; } /* copy buffer */ switch (src_info.format) { case TBM_FORMAT_YUV420: memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].size); memcpy(dst_info.planes[1].ptr, src_info.planes[1].ptr, src_info.planes[1].size); memcpy(dst_info.planes[2].ptr, src_info.planes[2].ptr, src_info.planes[2].size); break; case TBM_FORMAT_NV12: memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].stride * src_info.height); memcpy(dst_info.planes[1].ptr, src_info.planes[1].ptr, src_info.planes[0].stride * src_info.height / 2); break; default: LOGW("unsupported format"); break; } #ifdef _INTERNAL_DEBUG_ __dump_surf(flush_buffer->tbm_surf); g_cnt_out++; LOGD("flush_buffer dump is done"); #endif if (tbm_surface_unmap(src_tbm_surf)) LOGW("[src] unmap is failed"); if (tbm_surface_unmap(flush_buffer->tbm_surf)) LOGW("[dst] unmap is failed"); LOGW("copy is done. tbm surface : %p", flush_buffer->tbm_surf); evas_info->flush_buffer = flush_buffer; MMER_FLEAVE(); return MM_ERROR_NONE; ERROR: if (flush_buffer) { if (flush_buffer->tbm_surf) { tbm_surface_destroy(flush_buffer->tbm_surf); flush_buffer->tbm_surf = NULL; } free(flush_buffer); flush_buffer = NULL; } return MM_ERROR_EVASRENDER_INTERNAL; } /* release flush buffer */ static void _mm_evas_renderer_release_flush_buffer(mm_evas_info *evas_info) { MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); LOGW("release FLUSH BUFFER start"); if (evas_info->flush_buffer->bo) evas_info->flush_buffer->bo = NULL; if (evas_info->flush_buffer->tbm_surf) { tbm_surface_destroy(evas_info->flush_buffer->tbm_surf); evas_info->flush_buffer->tbm_surf = NULL; } LOGW("release FLUSH BUFFER done"); free(evas_info->flush_buffer); evas_info->flush_buffer = NULL; MMER_FLEAVE(); return; } static void _mm_evas_renderer_get_video_angle(mm_evas_info *evas_info, int *rotate_angle, int *orientation) { int rotate = 0; media_packet_h packet = NULL; media_packet_rotate_method_e org_orient = 0; MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); MMEVAS_RETURN_IF_FAIL(rotate_angle); MMEVAS_RETURN_IF_FAIL(orientation); rotate = evas_info->rotate; LOGD("current rotate value: %d", rotate); /* Counter clockwise */ switch (rotate) { case EVAS_IMAGE_ORIENT_0: //0 *rotate_angle = 0; break; case EVAS_IMAGE_ORIENT_90: //1 *rotate_angle = 90; break; case EVAS_IMAGE_ORIENT_180: //2 *rotate_angle = 180; break; case EVAS_IMAGE_ORIENT_270: //3 *rotate_angle = 270; break; default: LOGW("wrong angle type : %d", rotate); break; } LOGD("check display angle: %d", *rotate_angle); /* get content orientation */ packet = evas_info->pkt_info[evas_info->cur_idx].packet; MMEVAS_RETURN_IF_FAIL(packet); media_packet_get_rotate_method(packet, &org_orient); LOGE("get content orientation : %d", org_orient); /* Counter clockwise */ switch (org_orient) { case MEDIA_PACKET_ROTATE_IDENTITY: //0 *orientation = 0; break; case MEDIA_PACKET_ROTATE_90: //1 *orientation = 90; break; case MEDIA_PACKET_ROTATE_180: //2 *orientation = 180; break; case MEDIA_PACKET_ROTATE_270: //3 *orientation = 270; break; default: LOGW("wrong angle type : %d", org_orient); break; } LOGD("check orientation: %d", *orientation); return; } static void _mm_evas_renderer_update_rotate_angle(mm_evas_info *evas_info) { int required_angle = 0; /* Angle required for straight view */ int rotate_angle = 0; int orientation = 0; MMER_FENTER(); MMEVAS_RETURN_IF_FAIL(evas_info); _mm_evas_renderer_get_video_angle(evas_info, &rotate_angle, &orientation); required_angle = 360 - orientation; rotate_angle = (rotate_angle + required_angle) % 360; /* chech if supported or not */ if (rotate_angle % 90) { LOGD("not supported rotation angle = %d", rotate_angle); return; } switch (rotate_angle) { case 0: evas_info->rotate_angle = EVAS_IMAGE_ORIENT_0; break; case 90: evas_info->rotate_angle = EVAS_IMAGE_ORIENT_90; break; case 180: evas_info->rotate_angle = EVAS_IMAGE_ORIENT_180; break; case 270: evas_info->rotate_angle = EVAS_IMAGE_ORIENT_270; break; } LOGD("setting rotation angle : %d", evas_info->rotate_angle); return; } void mm_evas_renderer_write(media_packet_h packet, void *data) { MMER_FENTER(); if (!packet) { LOGE("packet %p is NULL", packet); return; } mm_evas_info *handle = (mm_evas_info *)data; int ret = MEDIA_PACKET_ERROR_NONE; bool has; tbm_surface_h tbm_surf; gint new_idx; LOGD("packet [%p]", packet); if (!data || !handle) { LOGE("handle %p or evas_info %p is NULL", data, handle); goto INVALID_PARAM; } g_mutex_lock(&handle->idx_lock); ret = media_packet_has_tbm_surface_buffer(packet, &has); if (ret != MEDIA_PACKET_ERROR_NONE) { LOGW("has_tbm_surface is failed"); goto ERROR; } /* FIXME: when setCaps occurs, _get_video_size should be called */ /* currently we are always checking it */ if (has && _get_video_size(packet, handle)) { /* Attention! if this error occurs, we need to consider managing buffer */ if (handle->sent_buffer_cnt > 3) { LOGE("too many buffers are not released %d", handle->sent_buffer_cnt); goto ERROR; } ret = media_packet_get_tbm_surface(packet, &tbm_surf); if (ret != MEDIA_PACKET_ERROR_NONE || !tbm_surf) { LOGW("get_tbm_surface is failed"); goto ERROR; } /* find new index for current packet */ new_idx = _find_empty_index(handle); if (new_idx == -1) goto ERROR; #ifdef _INTERNAL_DEBUG_ int ret2 = 0; if ((g_cnt_in%10 == 0) && (g_cnt_in < 500)) ret2 = __dump_pkt(packet, handle->w, handle->h); if (ret2) LOGW("__dump_pkt() is failed"); else g_cnt_in++; #endif /* save previous index */ handle->pkt_info[new_idx].prev_idx = handle->cur_idx; handle->pkt_info[new_idx].packet = packet; handle->pkt_info[new_idx].tbm_surf = tbm_surf; handle->cur_idx = new_idx; handle->sent_buffer_cnt++; LOGD("sent packet %d", handle->sent_buffer_cnt); ret = _mm_evas_pipe_write(handle, UPDATE_TBM_SURF); if (ret != MM_ERROR_NONE) { handle->pkt_info[new_idx].packet = NULL; handle->pkt_info[new_idx].tbm_surf = NULL; handle->pkt_info[new_idx].prev_idx = -1; handle->cur_idx = handle->pkt_info[new_idx].prev_idx; handle->sent_buffer_cnt--; LOGW("Failed to ecore_pipe_write() for updating tbm surf\n"); goto ERROR; } } else { LOGW("no tbm_surf"); goto ERROR; } g_mutex_unlock(&handle->idx_lock); MMER_FLEAVE(); return; ERROR: g_mutex_unlock(&handle->idx_lock); INVALID_PARAM: /* destroy media_packet immediately */ if (packet) { g_mutex_lock(&handle->mp_lock); LOGD("cant write. destroy packet [%p]", packet); if (handle && handle->packet_rendered_cb) { handle->packet_rendered_cb(packet, handle->packet_rendered_cb_user); } else { if (media_packet_destroy(packet) != MEDIA_PACKET_ERROR_NONE) LOGE("media_packet_destroy failed %p", packet); packet = NULL; } g_mutex_unlock(&handle->mp_lock); } return; } int mm_evas_renderer_create(MMHandleType *handle, Evas_Object *eo) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = NULL; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(handle, MM_ERROR_EVASRENDER_INVALID_ARGUMENT); MMEVAS_RETURN_VAL_IF_FAIL(eo, MM_ERROR_EVASRENDER_INVALID_ARGUMENT); ret = _mm_evas_renderer_create(&evas_info); if (ret != MM_ERROR_NONE) { LOGE("fail to create evas_info"); return ret; } ret = _mm_evas_renderer_set_info(evas_info, eo); if (ret != MM_ERROR_NONE) { LOGE("fail to init evas_info"); if (_mm_evas_renderer_destroy(&evas_info) != MM_ERROR_NONE) LOGE("fail to destroy evas_info"); return ret; } *handle = (MMHandleType)evas_info; return MM_ERROR_NONE; } int mm_evas_renderer_destroy(MMHandleType *handle) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = (mm_evas_info *)*handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); ret = _mm_evas_renderer_destroy(&evas_info); if (ret != MM_ERROR_NONE) { LOGE("fail to destroy evas_info"); return ret; } *handle = NULL; MMER_FLEAVE(); return MM_ERROR_NONE; } int mm_evas_renderer_set_visible(MMHandleType handle, bool visible) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); evas_info->visible = visible; ret = _mm_evas_pipe_write(evas_info, UPDATE_VISIBILITY); MMER_FLEAVE(); return ret; } int mm_evas_renderer_get_visible(MMHandleType handle, bool *visible) { mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); *visible = evas_info->visible; MMER_FLEAVE(); return MM_ERROR_NONE; } int mm_evas_renderer_set_rotation(MMHandleType handle, int rotate) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = (mm_evas_info *)handle; guint value; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); switch (rotate) { case DEGREE_0: value = EVAS_IMAGE_ORIENT_0; break; case DEGREE_90: value = EVAS_IMAGE_ORIENT_90; break; case DEGREE_180: value = EVAS_IMAGE_ORIENT_180; break; case DEGREE_270: value = EVAS_IMAGE_ORIENT_270; break; default: return MM_ERROR_EVASRENDER_INVALID_ARGUMENT; } if (evas_info->rotate != value) { evas_info->update_needed = TRUE; evas_info->rotate = value; } evas_info->rendering_info_changed = TRUE; ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF); MMER_FLEAVE(); return ret; } int mm_evas_renderer_get_rotation(MMHandleType handle, int *rotate) { mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); switch (evas_info->rotate) { case EVAS_IMAGE_ORIENT_0: *rotate = DEGREE_0; break; case EVAS_IMAGE_ORIENT_90: *rotate = DEGREE_90; break; case EVAS_IMAGE_ORIENT_180: *rotate = DEGREE_180; break; case EVAS_IMAGE_ORIENT_270: *rotate = DEGREE_270; break; default: return MM_ERROR_EVASRENDER_INVALID_ARGUMENT; } MMER_FLEAVE(); return MM_ERROR_NONE; } int mm_evas_renderer_set_geometry(MMHandleType handle, int mode) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); if (evas_info->display_geometry_method != mode) { evas_info->update_needed = TRUE; evas_info->pre_display_geometry_method = evas_info->display_geometry_method; evas_info->display_geometry_method = mode; } evas_info->rendering_info_changed = TRUE; /* ecore_pipe_write is needed, because of setting ratio for letterbox mode */ ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF); MMER_FLEAVE(); return ret; } int mm_evas_renderer_get_geometry(MMHandleType handle, int *mode) { mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); *mode = evas_info->display_geometry_method; MMER_FLEAVE(); return MM_ERROR_NONE; } int mm_evas_renderer_set_roi_area(MMHandleType handle, int x, int y, int w, int h) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); if (w <= 0 || h <= 0) { LOGE("invalid resolution w(%d), h(%d)", w, h); return MM_ERROR_EVASRENDER_INVALID_ARGUMENT; } if (evas_info->dst_roi.x != x || evas_info->dst_roi.y != y || evas_info->dst_roi.w != w || evas_info->dst_roi.h != h) { evas_info->dst_roi.x = x; evas_info->dst_roi.y = y; evas_info->dst_roi.w = w; evas_info->dst_roi.h = h; evas_info->update_needed = TRUE; evas_info->is_set_roi_area = TRUE; } evas_info->rendering_info_changed = TRUE; /* pipe_write could be needed because ratio can be changed on pause state */ ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF); MMER_FLEAVE(); return ret; } int mm_evas_renderer_get_roi_area(MMHandleType handle, int *x, int *y, int *w, int *h) { mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); *x = evas_info->dst_roi.x; *y = evas_info->dst_roi.y; *w = evas_info->dst_roi.w; *h = evas_info->dst_roi.h; MMER_FLEAVE(); return MM_ERROR_NONE; } int mm_evas_renderer_set_flip(MMHandleType handle, int flip) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = (mm_evas_info *)handle; guint value; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); switch (flip) { case FLIP_NONE: value = EVAS_IMAGE_ORIENT_NONE; break; case FLIP_HORIZONTAL: value = EVAS_IMAGE_FLIP_HORIZONTAL; break; case FLIP_VERTICAL: value = EVAS_IMAGE_FLIP_VERTICAL; break; case FLIP_BOTH: value = EVAS_IMAGE_ORIENT_180; break; default: return MM_ERROR_EVASRENDER_INVALID_ARGUMENT; } if (evas_info->flip != value) { evas_info->update_needed = TRUE; evas_info->flip = value; } ret = _mm_evas_pipe_write(evas_info, UPDATE_TBM_SURF); MMER_FLEAVE(); return ret; } int mm_evas_renderer_get_flip(MMHandleType handle, int *flip) { mm_evas_info *evas_info = (mm_evas_info *)handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); switch (evas_info->flip) { case EVAS_IMAGE_ORIENT_NONE: *flip = FLIP_NONE; break; case EVAS_IMAGE_FLIP_HORIZONTAL: *flip = FLIP_HORIZONTAL; break; case EVAS_IMAGE_FLIP_VERTICAL: *flip = FLIP_VERTICAL; break; case EVAS_IMAGE_ORIENT_180: *flip = FLIP_BOTH; break; default: return MM_ERROR_EVASRENDER_INVALID_ARGUMENT; } MMER_FLEAVE(); return MM_ERROR_NONE; } int mm_evas_renderer_retrieve_all_packets(MMHandleType handle, bool keep_screen) { int ret = MM_ERROR_NONE; mm_evas_info *evas_info = (mm_evas_info*) handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); ret = _mm_evas_renderer_retrieve_all_packets(evas_info, keep_screen); MMER_FLEAVE(); return ret; } int mm_evas_renderer_set_packet_rendered_callback(MMHandleType handle, mm_evas_renderer_media_packet_rendered_cb callback, void *user_data) { mm_evas_info *evas_info = (mm_evas_info*) handle; MMER_FENTER(); MMEVAS_RETURN_VAL_IF_FAIL(evas_info, MM_ERROR_EVASRENDER_NOT_INITIALIZED); evas_info->packet_rendered_cb = callback; evas_info->packet_rendered_cb_user = user_data; LOGW("set rendered callback %p, user_data %p", evas_info->packet_rendered_cb, evas_info->packet_rendered_cb_user); MMER_FLEAVE(); return MM_ERROR_NONE; }