Merge branch 'tizen_line_coverage' into tizen
[platform/core/api/mediacodec.git] / src / media_codec.c
old mode 100755 (executable)
new mode 100644 (file)
index 22cd3d8..cff7fc1
 
 #include <dlog.h>
 
+#define MC_PREALLOCATED_HANDLE_ARRAY_SIZE 16
+
+#ifdef USE_MM_RESOURCE_MANAGER
+static mm_resource_manager_h g_mc_resource_manager;
+static GPtrArray *g_mediacodec_handles;
+static GMutex g_mediacodec_lock;
+#endif
+
 static gboolean  __mediacodec_empty_buffer_cb(media_packet_h pkt, void *user_data);
 static gboolean __mediacodec_fill_buffer_cb(media_packet_h pkt, void *user_data);
 static gboolean __mediacodec_error_cb(mediacodec_error_e error, void *user_data);
 static gboolean __mediacodec_eos_cb(void *user_data);
 static gboolean __mediacodec_supported_codec_cb(mediacodec_codec_type_e codec_type, void *user_data);
 static gboolean __mediacodec_buffer_status_cb(mediacodec_status_e status, void *user_data);
+#ifdef USE_MM_RESOURCE_MANAGER
+static void __mediacodec_init_lib() __attribute__((constructor));
+static void __mediacodec_deinit_lib() __attribute__((destructor));
+static int __mediacodec_resource_release_cb(mm_resource_manager_h rm,
+               mm_resource_manager_res_h resource_h, void *user_data);
+#endif
 
 /*
  * Internal Implementation
@@ -121,17 +135,33 @@ int mediacodec_create(mediacodec_h *mediacodec)
 
        LOGD("mediacodec_create..");
 
+#ifdef USE_MM_RESOURCE_MANAGER
+       g_mutex_lock(&g_mediacodec_lock);
+
+       if (!g_mc_resource_manager) {
+               int mm_ret = mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
+                       __mediacodec_resource_release_cb, NULL, &g_mc_resource_manager);
+               if (mm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+                       g_mutex_unlock(&g_mediacodec_lock);
+                       LOGE("mm_resource_manager_create failed 0x%x", mm_ret);
+                       return MEDIACODEC_ERROR_INTERNAL;
+               }
+       }
+
+       g_mutex_unlock(&g_mediacodec_lock);
+#endif
+
        handle = (mediacodec_s *)malloc(sizeof(mediacodec_s));
        if (handle != NULL) {
                memset(handle, 0 , sizeof(mediacodec_s));
        } else {
-               LOGE("MEDIACODEC_ERROR_OUT_OF_MEMORY(0x%08x)", MEDIACODEC_ERROR_OUT_OF_MEMORY);
+               LOGE("MEDIACODEC_ERROR_OUT_OF_MEMORY(0x%08x)", MEDIACODEC_ERROR_OUT_OF_MEMORY); //LCOV_EXCL_LINE
                return MEDIACODEC_ERROR_OUT_OF_MEMORY;
        }
 
        ret = mc_create(&handle->mc_handle);
        if (ret != MEDIACODEC_ERROR_NONE) {
-               LOGE("MEDIACODEC_ERROR_INVALID_OPERATION(0x%08x)", MEDIACODEC_ERROR_INVALID_OPERATION);
+               LOGE("MEDIACODEC_ERROR_INVALID_OPERATION(0x%08x)", MEDIACODEC_ERROR_INVALID_OPERATION); //LCOV_EXCL_LINE
                handle->state = MEDIACODEC_STATE_NONE;
                g_free(handle->mc_handle);
                g_free(handle);
@@ -151,6 +181,12 @@ int mediacodec_create(mediacodec_h *mediacodec)
        mc_set_buffer_status_cb(handle->mc_handle, (mediacodec_buffer_status_cb)__mediacodec_buffer_status_cb, handle);
        mc_set_supported_codec_cb(handle->mc_handle, (mediacodec_supported_codec_cb)__mediacodec_supported_codec_cb, handle);
 
+#ifdef USE_MM_RESOURCE_MANAGER
+       g_mutex_lock(&g_mediacodec_lock);
+       g_ptr_array_insert(g_mediacodec_handles, -1, *mediacodec);
+       g_mutex_unlock(&g_mediacodec_lock);
+#endif
+
        return MEDIACODEC_ERROR_NONE;
 
 }
@@ -163,9 +199,15 @@ int mediacodec_destroy(mediacodec_h mediacodec)
 
        int ret = mc_destroy(handle->mc_handle);
        if (ret != MEDIACODEC_ERROR_NONE) {
-               LOGD("MEDIACODEC_ERROR_INVALID_OPERATION(0x%08x)", MEDIACODEC_ERROR_INVALID_OPERATION);
+               LOGD("MEDIACODEC_ERROR_INVALID_OPERATION(0x%08x)", MEDIACODEC_ERROR_INVALID_OPERATION); //LCOV_EXCL_LINE
                return MEDIACODEC_ERROR_INVALID_OPERATION;
        } else {
+#ifdef USE_MM_RESOURCE_MANAGER
+               g_mutex_lock(&g_mediacodec_lock);
+               g_ptr_array_remove_fast(g_mediacodec_handles, mediacodec);
+               g_mutex_unlock(&g_mediacodec_lock);
+#endif
+
                handle->state = MEDIACODEC_STATE_NONE;
                free(handle);
                handle = NULL;
@@ -253,12 +295,84 @@ int mediacodec_set_aenc_info(mediacodec_h mediacodec, int samplerate, int channe
        }
 }
 
+int mediacodec_configure_from_media_format(mediacodec_h mediacodec, media_format_h format, int flags)
+{
+       MEDIACODEC_INSTANCE_CHECK(mediacodec);
+       mediacodec_s *handle = (mediacodec_s *)mediacodec;
+       MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE);
+
+       int ret = mc_configure(handle->mc_handle, format, flags);
+
+       if (ret != MEDIACODEC_ERROR_NONE) {
+               return __convert_error_code(ret, (char *)__FUNCTION__);
+       } else {
+               handle->state = MEDIACODEC_STATE_IDLE;
+               return MEDIACODEC_ERROR_NONE;
+       }
+}
+
 int mediacodec_prepare(mediacodec_h mediacodec)
 {
        MEDIACODEC_INSTANCE_CHECK(mediacodec);
        mediacodec_s *handle = (mediacodec_s *)mediacodec;
+#ifdef USE_MM_RESOURCE_MANAGER
+       mc_handle_t *mc_handle = (mc_handle_t *) handle->mc_handle;
+       int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+       mm_resource_manager_res_h resource;
+#endif
        MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE);
 
+#ifdef USE_MM_RESOURCE_MANAGER
+       if (mc_handle->is_hw && mc_handle->is_video) {
+
+               if (handle->codec_resource) {
+                       LOGE("Codec resource is tried to be acquired twice\n"); //LCOV_EXCL_LINE
+                       return MC_INTERNAL_ERROR;
+               }
+
+               /*
+                * TODO
+                * Currently volume of requested resource is set to 1. Default
+                * capacity for video encoder/decoder is 1 too. The actual capacity
+                * should be set in mmfw-sysconf > mmfw_resource_manager.ini.
+                * If different encode/decode operation needs different volume of
+                * video encoder/decoder, '1' in the following
+                * mm_resource_manager_mark_for_acquire function should be set to
+                * corresponding value.
+                * If that value depends on platform where it's executed,
+                * MM_RESOURCE_MANAGER_RES_TYPE_COND_* and
+                * mm_resource_manager_get_res_type_volume() can be used.
+                * Additional info can be found in doxygen comments of mm_resource_manager.h
+                */
+//LCOV_EXCL_START
+               rm_ret = mm_resource_manager_mark_for_acquire(g_mc_resource_manager,
+                               mc_handle->is_encoder ?
+                               MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER :
+                               MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
+                               1, &resource);
+               if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+                       LOGE("Failed to acquire resource manager %x", rm_ret);
+                       switch (rm_ret) {
+                       case MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED:
+                               return MEDIACODEC_ERROR_NOT_SUPPORTED_ON_DEVICE;
+                       case MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH:
+                               return MEDIACODEC_ERROR_RESOURCE_OVERLOADED;
+                       default:
+                               return MEDIACODEC_ERROR_INTERNAL;
+                       }
+               }
+
+               rm_ret = mm_resource_manager_commit(g_mc_resource_manager);
+               if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+                       mm_resource_manager_mark_for_release(g_mc_resource_manager, resource);
+                       LOGE("Failed to commit resource manager : %x", rm_ret);
+                       return MEDIACODEC_ERROR_INTERNAL;
+               }
+               handle->codec_resource = resource;
+//LCOV_EXCL_STOP
+       }
+#endif
+
        int ret = mc_prepare(handle->mc_handle);
 
        if (ret != MEDIACODEC_ERROR_NONE) {
@@ -273,12 +387,37 @@ int mediacodec_unprepare(mediacodec_h mediacodec)
 {
        MEDIACODEC_INSTANCE_CHECK(mediacodec);
        mediacodec_s *handle = (mediacodec_s *)mediacodec;
+#ifdef USE_MM_RESOURCE_MANAGER
+       int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+#endif
 
        int ret = mc_unprepare(handle->mc_handle);
 
        if (ret != MEDIACODEC_ERROR_NONE) {
                return __convert_error_code(ret, (char *)__FUNCTION__);
        } else {
+#ifdef USE_MM_RESOURCE_MANAGER
+               if (handle->codec_resource != NULL) {
+//LCOV_EXCL_START
+                       mm_resource_manager_mark_for_release(g_mc_resource_manager,
+                                       handle->codec_resource);
+                       handle->codec_resource = NULL;
+                       rm_ret = mm_resource_manager_commit(g_mc_resource_manager);
+                       if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+                               mm_resource_manager_mark_for_release(g_mc_resource_manager, handle->codec_resource);
+                               switch (rm_ret) {
+                               case MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY:
+                                       return MEDIACODEC_ERROR_RESOURCE_OVERLOADED;
+                               default:
+                                       return MEDIACODEC_ERROR_INTERNAL;
+                               }
+                       }
+//LCOV_EXCL_STOP
+               } else {
+                       LOGD("No codec resource to release. Probably resource release cb called\n");
+               }
+#endif
+
                handle->state = MEDIACODEC_STATE_IDLE;
                return MEDIACODEC_ERROR_NONE;
        }
@@ -337,7 +476,8 @@ int mediacodec_get_supported_type(mediacodec_h mediacodec, mediacodec_codec_type
                return __convert_error_code(ret, (char *)__FUNCTION__);
        else
                handle->state = MEDIACODEC_STATE_IDLE;
-               return MEDIACODEC_ERROR_NONE;
+
+       return MEDIACODEC_ERROR_NONE;
 }
 
 int mediacodec_set_input_buffer_used_cb(mediacodec_h mediacodec, mediacodec_input_buffer_used_cb callback, void *user_data)
@@ -580,3 +720,60 @@ static gboolean __mediacodec_buffer_status_cb(mediacodec_status_e status, void *
 
        return 1;
 }
+
+#ifdef USE_MM_RESOURCE_MANAGER
+//LCOV_EXCL_START
+static int __mediacodec_resource_release_cb(mm_resource_manager_h rm,
+               mm_resource_manager_res_h resource_h, void *user_data)
+{
+       int i;
+       mediacodec_s *handle;
+
+       g_mutex_lock(&g_mediacodec_lock);
+       for (i = 0; i < g_mediacodec_handles->len; i++) {
+               handle = g_ptr_array_index(g_mediacodec_handles, i);
+               if (handle->codec_resource == resource_h) {
+                       /*
+                        * TODO
+                        * The resource release cb is asynchronous, so mediacodec_unprepare might be
+                        * called in this thread and in the main thread at the same time.
+                        * Mutex lock/unlock should be added in the body of mediacodec_unprepare() to
+                        * avoid the race condition.
+                        */
+                       handle->codec_resource = NULL;
+                       mediacodec_unprepare((mediacodec_h)handle);
+                       __mediacodec_error_cb(MEDIACODEC_ERROR_RESOURCE_CONFLICT, handle);
+                       break;
+               }
+       }
+       g_mutex_unlock(&g_mediacodec_lock);
+
+       return FALSE;
+}
+//LCOV_EXCL_STOP
+
+
+static void __mediacodec_init_lib()
+{
+       LOGD("START");
+
+       g_mutex_init(&g_mediacodec_lock);
+       g_mediacodec_handles = g_ptr_array_sized_new(MC_PREALLOCATED_HANDLE_ARRAY_SIZE);
+
+       LOGD("DONE");
+}
+
+static void __mediacodec_deinit_lib()
+{
+       LOGD("START");
+
+       if (g_mc_resource_manager != NULL)
+               mm_resource_manager_destroy(g_mc_resource_manager);
+
+       g_ptr_array_unref(g_mediacodec_handles);
+       g_mutex_clear(&g_mediacodec_lock);
+
+       LOGD("DONE");
+}
+#endif
+