Add new interface for video encode decision callback 74/239974/6 submit/tizen/20200818.102105
authorJeongmo Yang <jm80.yang@samsung.com>
Fri, 31 Jul 2020 06:40:47 +0000 (15:40 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Fri, 14 Aug 2020 05:04:48 +0000 (14:04 +0900)
[Version] 0.3.20
[Issue Type] New feature

Change-Id: Ie6b5b54ebc55dc1634497fc69ec9149bf190e6d3
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
legacy/include/legacy_recorder.h
legacy/include/legacy_recorder_private.h
legacy/src/legacy_recorder.c
muse/include/muse_recorder.h
muse/src/muse_recorder_dispatcher.c
packaging/mmsvc-recorder.spec

index d0bb2ee..554ff8d 100644 (file)
@@ -287,6 +287,20 @@ typedef void (*recorder_audio_stream_cb)(void *stream, int size, recorder_sample
 typedef void (*recorder_muxed_stream_cb)(void *stream, int size, unsigned long long offset, void *user_data);
 
 /**
+ * @brief Called when video stream data was being delivered just before encoding, \n
+ *        and it will be encoded if application returns @c true, otherwise dropped.
+ * @since_tizen 6.0
+ *
+ * @remarks This function is issued in the context of internal framework so the UI update code should not be directly invoked.
+ * @remarks The @a frame should not be released and it's available until the callback returns.
+ *
+ * @param[in] frame     The reference pointer to video stream data
+ * @param[in] user_data The user data passed from the callback registration function
+ * @see legacy_recorder_set_video_encode_decision_cb()
+ */
+typedef bool (*recorder_video_encode_decision_cb)(MMCamcorderVideoStreamDataType *frame, void *user_data);
+
+/**
  * @brief Called once for each supported video resolution.
  * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
  * @param[in] width         The video image width
@@ -1126,6 +1140,39 @@ int legacy_recorder_set_muxed_stream_cb(recorder_h recorder, recorder_muxed_stre
 int legacy_recorder_unset_muxed_stream_cb(recorder_h recorder);
 
 /**
+ * @brief Registers a callback function to be called when video stream data is delivered.
+ * @since_tizen 6.0
+ * @remarks This callback receives the video data before encoding, \n
+ *          and it will be encoded if application returns @c true, otherwise dropped.
+ * @param[in] recorder  The handle to the recorder
+ * @param[in] callback  The callback function to register
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #RECORDER_ERROR_NONE Successful
+ * @retval #RECORDER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RECORDER_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #RECORDER_ERROR_INVALID_STATE Invalid state
+ * @pre The recorder state should be #RECORDER_STATE_READY or #RECORDER_STATE_CREATED.
+ * @see recorder_unset_video_encode_decision_cb()
+ * @see recorder_video_encode_decision_stream_cb()
+ */
+int legacy_recorder_set_video_encode_decision_cb(recorder_h recorder, recorder_video_encode_decision_cb callback, void *user_data);
+
+/**
+ * @brief Unregisters the callback function.
+ * @since_tizen 6.0
+ * @param[in] recorder The handle to the media recorder
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #RECORDER_ERROR_NONE Successful
+ * @retval #RECORDER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RECORDER_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #RECORDER_ERROR_INVALID_STATE Invalid state
+ * @pre The recorder state should be #RECORDER_STATE_READY or #RECORDER_STATE_CREATED.
+ * @see recorder_set_video_encode_decision_cb()
+ */
+int legacy_recorder_unset_video_encode_decision_cb(recorder_h recorder);
+
+/**
  * @brief Registers a callback function to be invoked when the recording information changes.
  * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
  * @param[in]  recorder   The handle to the media recorder
index bf6cc5f..22bba1d 100644 (file)
@@ -53,6 +53,7 @@ typedef enum {
        _RECORDER_EVENT_TYPE_INTERRUPTED,
        _RECORDER_EVENT_TYPE_AUDIO_STREAM,
        _RECORDER_EVENT_TYPE_MUXED_STREAM,
+       _RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION,
        _RECORDER_EVENT_TYPE_ERROR,
        _RECORDER_EVENT_TYPE_INTERRUPT_STARTED,
        _RECORDER_EVENT_TYPE_NUM
index ac4ee10..2136ece 100644 (file)
@@ -50,6 +50,7 @@ int _camera_set_use(camera_h camera, bool used);
 
 static int __mm_audio_stream_cb(MMCamcorderAudioStreamDataType *stream, void *user_param);
 static int __mm_muxed_stream_cb(MMCamcorderMuxedStreamDataType *stream, void *user_param);
+static int __mm_video_encode_decision_cb(MMCamcorderVideoStreamDataType *stream, void *user_param);
 static int __mm_recorder_msg_cb(int message, void *param, void *user_data);
 
 
@@ -422,6 +423,27 @@ static int __mm_muxed_stream_cb(MMCamcorderMuxedStreamDataType *stream, void *us
 }
 
 
+static int __mm_video_encode_decision_cb(MMCamcorderVideoStreamDataType *stream, void *user_param)
+{
+       recorder_s *handle = (recorder_s *)user_param;
+       int type = _RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION;
+       bool do_encode = true;
+
+       recorder_return_val_if_fail(handle && stream, 0);
+
+       if (!handle->user_cb[type]) {
+               LOGW("video_encode_decision_cb is NULL");
+               return true;
+       }
+
+       do_encode = ((recorder_video_encode_decision_cb)(handle->user_cb[type]))(stream, handle->user_data[type]);
+
+       LOGD("%d", do_encode);
+
+       return (int)do_encode;
+}
+
+
 static int _recorder_check_and_set_attribute(recorder_h recorder, const char *attribute_name, int set_value)
 {
        bool reset_pipeline = false;
@@ -1179,6 +1201,50 @@ int legacy_recorder_unset_muxed_stream_cb(recorder_h recorder)
 }
 
 
+int legacy_recorder_set_video_encode_decision_cb(recorder_h recorder, recorder_video_encode_decision_cb callback, void *user_data)
+{
+       int ret = MM_ERROR_NONE;
+       recorder_s *handle = (recorder_s *)recorder;
+       recorder_state_e state = RECORDER_STATE_NONE;
+
+       recorder_return_val_if_fail(handle && callback, RECORDER_ERROR_INVALID_PARAMETER);
+       recorder_return_val_if_fail(handle->camera_device_count > 0, RECORDER_ERROR_NOT_SUPPORTED);
+
+       legacy_recorder_get_state(recorder, &state);
+       recorder_return_val_if_fail(state <= RECORDER_STATE_READY, RECORDER_ERROR_INVALID_STATE);
+
+       ret = mm_camcorder_set_video_encode_decision_callback(handle->mm_handle, __mm_video_encode_decision_cb, handle);
+       if (ret == MM_ERROR_NONE) {
+               handle->user_cb[_RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION] = callback;
+               handle->user_data[_RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION] = user_data;
+       }
+
+       return __convert_recorder_error_code(__func__, ret);
+}
+
+
+int legacy_recorder_unset_video_encode_decision_cb(recorder_h recorder)
+{
+       int ret = MM_ERROR_NONE;
+       recorder_s *handle = (recorder_s *)recorder;
+       recorder_state_e state = RECORDER_STATE_NONE;
+
+       recorder_return_val_if_fail(handle, RECORDER_ERROR_INVALID_PARAMETER);
+       recorder_return_val_if_fail(handle->camera_device_count > 0, RECORDER_ERROR_NOT_SUPPORTED);
+
+       legacy_recorder_get_state(recorder, &state);
+       recorder_return_val_if_fail(state <= RECORDER_STATE_READY, RECORDER_ERROR_INVALID_STATE);
+
+       ret = mm_camcorder_set_video_encode_decision_callback(handle->mm_handle, NULL, NULL);
+       if (ret == MM_ERROR_NONE) {
+               handle->user_cb[_RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION] = NULL;
+               handle->user_data[_RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION] = NULL;
+       }
+
+       return __convert_recorder_error_code(__func__, ret);
+}
+
+
 int legacy_recorder_set_error_cb(recorder_h recorder, recorder_error_cb callback, void *user_data)
 {
        recorder_s *handle = (recorder_s *)recorder;
index 5c69c88..9b51156 100644 (file)
@@ -102,7 +102,9 @@ typedef enum {
        MUSE_RECORDER_API_UNSET_MUXED_STREAM_CB, /* 65 */
        MUSE_RECORDER_API_SET_INTERRUPT_STARTED_CB,
        MUSE_RECORDER_API_UNSET_INTERRUPT_STARTED_CB,
-       MUSE_RECORDER_API_MAX
+       MUSE_RECORDER_API_SET_VIDEO_ENCODE_DECISION_CB,
+       MUSE_RECORDER_API_UNSET_VIDEO_ENCODE_DECISION_CB,
+       MUSE_RECORDER_API_MAX /* 70 */
 } muse_recorder_api_e;
 
 /**
@@ -130,6 +132,7 @@ typedef enum {
        MUSE_RECORDER_EVENT_TYPE_FOREACH_SUPPORTED_VIDEO_ENCODER,
        MUSE_RECORDER_EVENT_TYPE_FOREACH_SUPPORTED_VIDEO_RESOLUTION,
        MUSE_RECORDER_EVENT_TYPE_INTERRUPT_STARTED,
+       MUSE_RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION,
        MUSE_RECORDER_EVENT_TYPE_NUM
 } muse_recorder_event_e;
 
@@ -167,6 +170,15 @@ typedef enum {
        MUSE_RECORDER_SOURCE_TYPE_CAMERA,
 } muse_recorder_source_type_e;
 
+/**
+ * @brief The structure type for muse recorder buffer type.
+ */
+typedef enum {
+       MUSE_RECORDER_BUFFER_TYPE_AUDIO_STREAM,
+       MUSE_RECORDER_BUFFER_TYPE_MUXED_STREAM,
+       MUSE_RECORDER_BUFFER_TYPE_VIDEO_ENCODE_DECISION
+} muse_recorder_buffer_type_e;
+
 
 /**
  * @brief Definition for the callback event id.
index c024525..a89b9f8 100644 (file)
@@ -81,14 +81,22 @@ typedef struct {
        tbm_fd fd;
 } muse_recorder_export_data;
 
+typedef struct {
+       GList *list;
+       GMutex lock;
+       GCond cond;
+} muse_recorder_data_list;
+
 /**
  * @brief The structure type for the muse recorder.
  */
 typedef struct {
        recorder_h recorder_handle;
        tbm_bufmgr bufmgr;
-       GList *data_list;
        GMutex list_lock;
+       muse_recorder_data_list recorder_data;
+       muse_camera_data_list camera_data;
+       bool video_encode_decision;
        muse_recorder_type_e type;
 } muse_recorder_handle_s;
 
@@ -335,9 +343,9 @@ void _recorder_disp_audio_stream_cb(void* stream, int size, recorder_sample_type
        export_data->bo = bo;
 
        /* add bo info to list */
-       g_mutex_lock(&muse_recorder->list_lock);
-       muse_recorder->data_list = g_list_append(muse_recorder->data_list, (gpointer)export_data);
-       g_mutex_unlock(&muse_recorder->list_lock);
+       g_mutex_lock(&muse_recorder->recorder_data.lock);
+       muse_recorder->recorder_data.list = g_list_append(muse_recorder->recorder_data.list, (gpointer)export_data);
+       g_mutex_unlock(&muse_recorder->recorder_data.lock);
 
        /* send message */
        muse_recorder_msg_event5_fd(MUSE_RECORDER_CB_EVENT,
@@ -408,9 +416,9 @@ void _recorder_disp_muxed_stream_cb(void* stream, int size, unsigned long long o
        export_data->bo = bo;
 
        /* add bo info to list */
-       g_mutex_lock(&muse_recorder->list_lock);
-       muse_recorder->data_list = g_list_append(muse_recorder->data_list, (gpointer)export_data);
-       g_mutex_unlock(&muse_recorder->list_lock);
+       g_mutex_lock(&muse_recorder->recorder_data.lock);
+       muse_recorder->recorder_data.list = g_list_append(muse_recorder->recorder_data.list, (gpointer)export_data);
+       g_mutex_unlock(&muse_recorder->recorder_data.lock);
 
        /* send message */
        muse_recorder_msg_event3_fd(MUSE_RECORDER_CB_EVENT,
@@ -438,6 +446,59 @@ _MUXED_STREAM_CB_ERROR:
        return;
 }
 
+bool _recorder_disp_video_encode_decision_cb(void *stream, void *user_data)
+{
+       int send_ret = 0;
+       char *send_message = NULL;
+       muse_recorder_handle_s *muse_recorder = NULL;
+       muse_camera_export_data *export_data = NULL;
+       muse_module_h module = (muse_module_h)user_data;
+       tbm_fd tfd[MUSE_NUM_FD] = {-1, -1, -1, -1};
+       gint64 end_time = 0;
+
+       /*LOGD("Enter");*/
+
+       muse_recorder = (muse_recorder_handle_s *)muse_server_ipc_get_handle(module);
+
+       recorder_return_val_if_fail(muse_recorder, true);
+
+       export_data = camera_export_data_new(stream, muse_recorder->bufmgr, tfd);
+       if (!export_data) {
+               LOGE("export_data failed");
+               return true;
+       }
+
+       /* add bo info to list */
+       g_mutex_lock(&muse_recorder->camera_data.lock);
+
+       muse_recorder->camera_data.list = g_list_append(muse_recorder->camera_data.list, (gpointer)export_data);
+
+       /* reset decision */
+       muse_recorder->video_encode_decision = true;
+
+       /* send message */
+       send_message = muse_core_msg_new(MUSE_RECORDER_CB_EVENT,
+               MUSE_TYPE_INT, PARAM_EVENT, MUSE_RECORDER_EVENT_TYPE_VIDEO_ENCODE_DECISION,
+               MUSE_TYPE_INT, PARAM_EVENT_CLASS, MUSE_CAMERA_EVENT_CLASS_THREAD_SUB,
+               MUSE_TYPE_INT, "video_fd", tfd[0],
+               MUSE_TYPE_INT, "num_buffer_fd", export_data->num_buffer_fd,
+               0);
+
+       send_ret = muse_core_msg_send_fd(muse_server_module_get_msg_fd(module), (int *)tfd, send_message);
+
+       muse_core_msg_free(send_message);
+
+       end_time = g_get_monotonic_time() + G_TIME_SPAN_SECOND;
+       if (!g_cond_wait_until(&muse_recorder->camera_data.cond, &muse_recorder->camera_data.lock, end_time))
+               LOGW("video encode decision callback return message timeout");
+
+       g_mutex_unlock(&muse_recorder->camera_data.lock);
+
+       LOGD("returned video_encode_decision %d", muse_recorder->video_encode_decision);
+
+       return muse_recorder->video_encode_decision;
+}
+
 bool _recorder_disp_foreach_supported_video_resolution_cb(int width, int height, void *user_data)
 {
        muse_module_h module = (muse_module_h)user_data;
@@ -499,70 +560,70 @@ bool _recorder_disp_foreach_supported_video_encoder_cb(recorder_video_codec_e co
        return true;
 }
 
-static int _recorder_remove_export_data(muse_module_h module, tbm_fd fd, int remove_all)
-{
-       muse_recorder_handle_s *muse_recorder = NULL;
-       GList *tmp_list = NULL;
-       muse_recorder_export_data *export_data = NULL;
-
-       recorder_return_val_if_fail(module && (fd >= 0 || remove_all), FALSE);
-
-       muse_recorder = (muse_recorder_handle_s *)muse_server_ipc_get_handle(module);
 
-       recorder_return_val_if_fail(muse_recorder, FALSE);
+static void _recorder_export_data_free(gpointer data)
+{
+       muse_recorder_export_data *export_data = (muse_recorder_export_data *)data;
 
-       g_mutex_lock(&muse_recorder->list_lock);
+       if (!export_data)
+               return;
 
-       tmp_list = muse_recorder->data_list;
+       LOGD("fd[%d], bo[%p]", export_data->fd, export_data->bo);
 
-       while (tmp_list) {
-               export_data = (muse_recorder_export_data *)tmp_list->data;
+       /* unref bo */
+       if (export_data->bo) {
+               tbm_bo_unref(export_data->bo);
+               export_data->bo = NULL;
+       } else {
+               LOGW("bo for fd[%d] is NULL", export_data->fd);
+       }
 
-               tmp_list = tmp_list->next;
+       /* close exported fd */
+       if (export_data->fd > -1) {
+               /*LOGD("close export_data->fd %d", export_data->fd);*/
+               close(export_data->fd);
+               export_data->fd = -1;
+       }
 
-               if (export_data == NULL) {
-                       LOGW("NULL data");
-                       continue;
-               }
+       g_free(export_data);
+}
 
-               if (export_data->fd != fd && remove_all == FALSE)
-                       continue;
 
-               /*LOGD("fd %d matched, remove it (remove_all %d)", fd, remove_all);*/
+static int _recorder_export_data_compare(gconstpointer data, gconstpointer fd_to_find)
+{
+       LOGD("%d : %d", ((muse_recorder_export_data *)data)->fd, GPOINTER_TO_INT(fd_to_find));
+       return (((muse_recorder_export_data *)data)->fd != GPOINTER_TO_INT(fd_to_find));
+}
 
-               if (export_data->bo) {
-                       tbm_bo_unref(export_data->bo);
-                       export_data->bo = NULL;
-               } else {
-                       LOGW("bo for fd %d is NULL", fd);
-               }
 
-               /* close exported fd */
-               close(export_data->fd);
-               export_data->fd = -1;
+static gboolean _recorder_remove_export_data(muse_recorder_data_list *recorder_data, tbm_fd fd)
+{
+       GList *found_item = NULL;
 
-               muse_recorder->data_list = g_list_remove(muse_recorder->data_list, export_data);
+       recorder_return_val_if_fail(recorder_data, FALSE);
+       recorder_return_val_if_fail(fd >= -1, FALSE); /* -1 means "Remove all". */
 
-               g_free(export_data);
-               export_data = NULL;
+       g_mutex_lock(&recorder_data->lock);
 
-               if (remove_all == FALSE) {
-                       /*LOGD("fd %d, remove done", fd);*/
-                       g_mutex_unlock(&muse_recorder->list_lock);
-                       return TRUE;
-               } else {
-                       LOGD("check next data");
+       if (fd == -1) {
+               g_list_free_full(recorder_data->list, _recorder_export_data_free);
+               recorder_data->list = NULL;
+       } else {
+               found_item = g_list_find_custom(recorder_data->list,
+                       GINT_TO_POINTER(fd), _recorder_export_data_compare);
+               if (!found_item) {
+                       LOGE("could not find data for fd[%d]", fd);
+                       g_mutex_unlock(&recorder_data->lock);
+                       return FALSE;
                }
-       }
 
-       g_mutex_unlock(&muse_recorder->list_lock);
+               recorder_data->list = g_list_remove_link(recorder_data->list, found_item);
+               g_list_free_full(found_item, _recorder_export_data_free);
+       }
 
-       if (remove_all)
-               LOGD("remove all done");
-       else
-               LOGE("should not be reached here - fd %d", fd);
+       g_mutex_unlock(&recorder_data->lock);
 
-       return FALSE;
+       return TRUE;
 }
 
 
@@ -608,7 +669,10 @@ int recorder_dispatcher_create(muse_module_h module)
        muse_recorder = g_new0(muse_recorder_handle_s, 1);
 
        muse_recorder->type = recorder_type;
-       g_mutex_init(&muse_recorder->list_lock);
+       g_mutex_init(&muse_recorder->recorder_data.lock);
+       g_cond_init(&muse_recorder->recorder_data.cond);
+       g_mutex_init(&muse_recorder->camera_data.lock);
+       g_cond_init(&muse_recorder->camera_data.cond);
 
        if (muse_server_ipc_get_bufmgr(&muse_recorder->bufmgr) != MM_ERROR_NONE ||
                muse_server_ipc_get_gdbus_connection((GDBusConnection **)&gdbus_connection) != MM_ERROR_NONE) {
@@ -678,7 +742,11 @@ _CREATE_ERROR:
                muse_recorder->recorder_handle = NULL;
        }
 
-       g_mutex_clear(&muse_recorder->list_lock);
+       g_cond_init(&muse_recorder->camera_data.cond);
+       g_mutex_init(&muse_recorder->camera_data.lock);
+       g_cond_init(&muse_recorder->recorder_data.cond);
+       g_mutex_init(&muse_recorder->recorder_data.lock);
+
        g_free(muse_recorder);
 
        LOGE("error 0x%x", ret);
@@ -702,9 +770,13 @@ int recorder_dispatcher_destroy(muse_module_h module)
 
        ret = legacy_recorder_destroy(muse_recorder->recorder_handle);
        if (ret == RECORDER_ERROR_NONE) {
-               _recorder_remove_export_data(module, 0, TRUE);
+               _recorder_remove_export_data(&muse_recorder->recorder_data, -1);
+               camera_remove_export_data(&muse_recorder->camera_data, -1);
 
-               g_mutex_clear(&muse_recorder->list_lock);
+               g_cond_clear(&muse_recorder->camera_data.cond);
+               g_mutex_clear(&muse_recorder->camera_data.lock);
+               g_cond_clear(&muse_recorder->recorder_data.cond);
+               g_mutex_clear(&muse_recorder->recorder_data.lock);
 
                muse_recorder->bufmgr = NULL;
 
@@ -1988,6 +2060,8 @@ int recorder_dispatcher_attr_set_root_directory(muse_module_h module)
 int recorder_dispatcher_return_buffer(muse_module_h module)
 {
        int ret_fd = -1;
+       int video_encode_decision = 1;
+       muse_recorder_buffer_type_e buffer_type = MUSE_RECORDER_BUFFER_TYPE_AUDIO_STREAM;
        muse_recorder_handle_s *muse_recorder = NULL;
 
        muse_recorder = (muse_recorder_handle_s *)muse_server_ipc_get_handle(module);
@@ -1995,11 +2069,26 @@ int recorder_dispatcher_return_buffer(muse_module_h module)
        recorder_return_val_if_fail(muse_recorder, MUSE_RECORDER_ERROR_NONE);
 
        muse_recorder_msg_get(ret_fd, muse_server_module_get_msg(module));
+       muse_recorder_msg_get(buffer_type, muse_server_module_get_msg(module));
+
+       /*LOGD("handle[%p] buffer type[%d] ret_fd[%d]", muse_recorder, buffer_type, ret_fd);*/
+
+       if (buffer_type == MUSE_RECORDER_BUFFER_TYPE_VIDEO_ENCODE_DECISION) {
+               /* get decision and send signal */
+               muse_recorder_msg_get(video_encode_decision, muse_server_module_get_msg(module));
 
-       /*LOGD("handle : %p, ret_fd : %d", muse_recorder, ret_fd);*/
+               g_mutex_lock(&muse_recorder->camera_data.lock);
+               muse_recorder->video_encode_decision = (bool)video_encode_decision;
+               /*LOGD("video_encode_decision[%d]", video_encode_decision);*/
+               g_cond_signal(&muse_recorder->camera_data.cond);
+               g_mutex_unlock(&muse_recorder->camera_data.lock);
 
-       if (!_recorder_remove_export_data(module, (tbm_fd)ret_fd, FALSE))
-               LOGE("remove export data failed : fd %d", ret_fd);
+               if (!camera_remove_export_data(&muse_recorder->camera_data, (tbm_fd)ret_fd))
+                       LOGE("remove export data for video encode decision failed. fd[%d]", ret_fd);
+       } else {
+               if (!_recorder_remove_export_data(&muse_recorder->recorder_data, (tbm_fd)ret_fd))
+                       LOGE("remove export data failed. buffer type[%d] fd[%d]", buffer_type, ret_fd);
+       }
 
        return MUSE_RECORDER_ERROR_NONE;
 }
@@ -2121,6 +2210,45 @@ int recorder_dispatcher_unset_muxed_stream_cb(muse_module_h module)
 }
 
 
+int recorder_dispatcher_set_video_encode_decision_cb(muse_module_h module)
+{
+       int ret = RECORDER_ERROR_NONE;
+       muse_recorder_api_e api = MUSE_RECORDER_API_SET_VIDEO_ENCODE_DECISION_CB;
+       muse_recorder_api_class_e class = MUSE_RECORDER_API_CLASS_IMMEDIATE;
+       muse_recorder_handle_s *muse_recorder = NULL;
+
+       muse_recorder = (muse_recorder_handle_s *)muse_server_ipc_get_handle(module);
+
+       recorder_send_msg_return_err_if_fail(muse_recorder, RECORDER_ERROR_INVALID_OPERATION, MUSE_RECORDER_ERROR_NONE);
+
+       ret = legacy_recorder_set_video_encode_decision_cb(muse_recorder->recorder_handle,
+               (recorder_video_encode_decision_cb)_recorder_disp_video_encode_decision_cb, (void *)module);
+
+       muse_recorder_msg_return(api, class, ret, module);
+
+       return MUSE_RECORDER_ERROR_NONE;
+}
+
+
+int recorder_dispatcher_unset_video_encode_decision_cb(muse_module_h module)
+{
+       int ret = RECORDER_ERROR_NONE;
+       muse_recorder_api_e api = MUSE_RECORDER_API_UNSET_MUXED_STREAM_CB;
+       muse_recorder_api_class_e class = MUSE_RECORDER_API_CLASS_IMMEDIATE;
+       muse_recorder_handle_s *muse_recorder = NULL;
+
+       muse_recorder = (muse_recorder_handle_s *)muse_server_ipc_get_handle(module);
+
+       recorder_send_msg_return_err_if_fail(muse_recorder, RECORDER_ERROR_INVALID_OPERATION, MUSE_RECORDER_ERROR_NONE);
+
+       ret = legacy_recorder_unset_video_encode_decision_cb(muse_recorder->recorder_handle);
+
+       muse_recorder_msg_return(api, class, ret, module);
+
+       return MUSE_RECORDER_ERROR_NONE;
+}
+
+
 int (*dispatcher[MUSE_RECORDER_API_MAX]) (muse_module_h module) = {
        recorder_dispatcher_create, /* MUSE_RECORDER_API_CREATE */
        recorder_dispatcher_destroy, /* MUSE_RECORDER_API_DESTROY */
@@ -2189,7 +2317,9 @@ int (*dispatcher[MUSE_RECORDER_API_MAX]) (muse_module_h module) = {
        recorder_dispatcher_set_muxed_stream_cb, /* MUSE_RECORDER_API_SET_MUXED_STREAM_CB */
        recorder_dispatcher_unset_muxed_stream_cb, /* MUSE_RECORDER_API_UNSET_MUXED_STREAM_CB */
        recorder_dispatcher_set_interrupt_started_cb, /* MUSE_RECORDER_API_SET_INTERRUPT_STARTED_CB */
-       recorder_dispatcher_unset_interrupt_started_cb /* MUSE_RECORDER_API_UNSET_INTERRUPT_STARTED_CB */
+       recorder_dispatcher_unset_interrupt_started_cb, /* MUSE_RECORDER_API_UNSET_INTERRUPT_STARTED_CB */
+       recorder_dispatcher_set_video_encode_decision_cb, /* MUSE_RECORDER_API_SET_VIDEO_ENCODE_DECISION_CB */
+       recorder_dispatcher_unset_video_encode_decision_cb /* MUSE_RECORDER_API_UNSET_VIDEO_ENCODE_DECISION_CB */
 };
 
 
@@ -2257,9 +2387,13 @@ static int recorder_cmd_dispatcher_shutdown(muse_module_h module)
        case RECORDER_STATE_CREATED:
                ret = legacy_recorder_destroy(muse_recorder->recorder_handle);
                if (ret == RECORDER_ERROR_NONE) {
-                       _recorder_remove_export_data(module, 0, TRUE);
+                       _recorder_remove_export_data(&muse_recorder->recorder_data, -1);
+                       camera_remove_export_data(&muse_recorder->camera_data, -1);
 
-                       g_mutex_clear(&muse_recorder->list_lock);
+                       g_cond_clear(&muse_recorder->camera_data.cond);
+                       g_mutex_clear(&muse_recorder->camera_data.lock);
+                       g_cond_clear(&muse_recorder->recorder_data.cond);
+                       g_mutex_clear(&muse_recorder->recorder_data.lock);
 
                        muse_recorder->bufmgr = NULL;
 
index d69a745..caec0e9 100644 (file)
@@ -1,6 +1,6 @@
 Name:       mmsvc-recorder
 Summary:    A Recorder module for muse server
-Version:    0.3.19
+Version:    0.3.20
 Release:    0
 Group:      Multimedia/Libraries
 License:    Apache-2.0