From: Eunhae Choi Date: Fri, 1 Dec 2017 03:07:04 +0000 (+0900) Subject: [0.6.64] handle the gst msg in seperate thread X-Git-Tag: submit/tizen_3.0/20171201.071736^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ca17327d43b1ca75e57d1644093bf97c0b97124e;p=platform%2Fcore%2Fmultimedia%2Flibmm-player.git [0.6.64] handle the gst msg in seperate thread - remove bus watch not to use main loop - add new thread for handling the bus msg Change-Id: I83988effec1cf97e1e1f272a28bc0fa9d6529370 --- diff --git a/packaging/libmm-player.spec b/packaging/libmm-player.spec index eaa2844..45b0148 100644 --- a/packaging/libmm-player.spec +++ b/packaging/libmm-player.spec @@ -1,6 +1,6 @@ Name: libmm-player Summary: Multimedia Framework Player Library -Version: 0.6.63 +Version: 0.6.64 Release: 0 Group: Multimedia/Libraries License: Apache-2.0 diff --git a/src/include/mm_player_priv.h b/src/include/mm_player_priv.h index 54bec62..7df737f 100644 --- a/src/include/mm_player_priv.h +++ b/src/include/mm_player_priv.h @@ -399,11 +399,6 @@ typedef struct { bool media_packet_video_stream; } MMPlayerSetMode; -typedef struct { - GMainContext *global_default; - GMainContext *thread_default; -} MMPlayerGMainContext; - typedef struct { gint uri_idx; GList *uri_list; @@ -493,6 +488,12 @@ typedef struct { MMPlayerVideoColorspace video_cs; MMVideoBuffer captured; + /* gst bus msg thread, create during realize */ + GThread* bus_msg_thread; + gboolean bus_msg_thread_exit; + GCond bus_msg_thread_cond; + GMutex bus_msg_thread_mutex; + /* fakesink handling lock */ GMutex fsink_lock; @@ -652,8 +653,7 @@ typedef struct { /* signal notifiers */ GList* signals[MM_PLAYER_SIGNAL_TYPE_MAX]; - guint bus_watcher; - MMPlayerGMainContext context; + GMainContext *global_default; MMPlayerUriList uri_info; gboolean is_sound_extraction; @@ -864,6 +864,8 @@ int __mmplayer_set_state(mm_player_t* player, int state); int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command); gboolean __mmplayer_dump_pipeline_state(mm_player_t* player); void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id); +void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer); + /* util */ const gchar * __get_state_name(int state); gboolean __mmplayer_can_do_interrupt(mm_player_t *player); diff --git a/src/include/mm_player_utils.h b/src/include/mm_player_utils.h index cf4d2ac..9f00384 100644 --- a/src/include/mm_player_utils.h +++ b/src/include/mm_player_utils.h @@ -84,6 +84,13 @@ do { \ #define MMPLAYER_REPEAT_THREAD_WAIT(x_player) g_cond_wait(&((mm_player_t *)x_player)->repeat_thread_cond, &((mm_player_t *)x_player)->repeat_thread_mutex) #define MMPLAYER_REPEAT_THREAD_SIGNAL(x_player) g_cond_signal(&((mm_player_t *)x_player)->repeat_thread_cond); +/* gst bus msg thread */ +#define MMPLAYER_BUS_MSG_THREAD_LOCK(x_player) g_mutex_lock(&((mm_player_t *)x_player)->bus_msg_thread_mutex) +#define MMPLAYER_BUS_MSG_THREAD_UNLOCK(x_player) g_mutex_unlock(&((mm_player_t *)x_player)->bus_msg_thread_mutex) +#define MMPLAYER_BUS_MSG_THREAD_WAIT(x_player) g_cond_wait(&((mm_player_t *)x_player)->bus_msg_thread_cond, &((mm_player_t *)x_player)->bus_msg_thread_mutex) +#define MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(x_player, end_time) g_cond_wait_until(&((mm_player_t *)x_player)->bus_msg_thread_cond, &((mm_player_t *)x_player)->bus_msg_thread_mutex, end_time) +#define MMPLAYER_BUS_MSG_THREAD_SIGNAL(x_player) g_cond_signal(&((mm_player_t *)x_player)->bus_msg_thread_cond); + /* handling fakesink */ #define MMPLAYER_FSINK_LOCK(x_player) g_mutex_lock(&((mm_player_t *)x_player)->fsink_lock) #define MMPLAYER_FSINK_UNLOCK(x_player) g_mutex_unlock(&((mm_player_t *)x_player)->fsink_lock) diff --git a/src/mm_player.c b/src/mm_player.c index b420446..f5e9c08 100644 --- a/src/mm_player.c +++ b/src/mm_player.c @@ -108,24 +108,23 @@ int mm_player_destroy(MMHandleType player) MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_CMD_LOCK( player ); + /* destroy the gst bus msg thread if it is remained. + this funct have to be called before getting cmd lock. */ + _mmplayer_bus_msg_thread_destroy(player); + + MMPLAYER_CMD_LOCK(player); result = _mmplayer_destroy(player); MMPLAYER_CMD_UNLOCK(player); - /* to make sure unlocked. - @see __mmplayer_gst_callback, GST_MESSAGE_BUFFERING handling */ - MMPLAYER_CMD_LOCK(player); - MMPLAYER_CMD_UNLOCK( player ); - g_mutex_clear(&((mm_player_t*)player)->cmd_lock); g_mutex_clear(&((mm_player_t*)player)->playback_lock); - memset( (mm_player_t*)player, 0x00, sizeof(mm_player_t) ); + memset((mm_player_t*)player, 0x00, sizeof(mm_player_t)); /* free player */ - g_free( (void*)player ); + g_free((void*)player); return result; } @@ -182,7 +181,7 @@ int mm_player_unrealize(MMHandleType player) MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - MMPLAYER_CMD_LOCK( player ); + MMPLAYER_CMD_LOCK(player); result = _mmplayer_unrealize(player); diff --git a/src/mm_player_priv.c b/src/mm_player_priv.c index fc52174..c2e6732 100644 --- a/src/mm_player_priv.c +++ b/src/mm_player_priv.c @@ -174,7 +174,7 @@ static void __mmplayer_release_misc(mm_player_t* player); static void __mmplayer_release_misc_post(mm_player_t* player); static gboolean __mmplayer_init_gstreamer(mm_player_t* player); static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data); -static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data); +static void __mmplayer_gst_callback(GstMessage *msg, gpointer data); static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg); static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg); @@ -1104,15 +1104,83 @@ __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop) } } -static gboolean -__mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ +void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer) { - mm_player_t* player = (mm_player_t*) data; - gboolean ret = TRUE; + mm_player_t* player = (mm_player_t*)hplayer; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); + + /* destroy the gst bus msg thread */ + if (player->bus_msg_thread) { + MMPLAYER_BUS_MSG_THREAD_LOCK(player); + player->bus_msg_thread_exit = TRUE; + MMPLAYER_BUS_MSG_THREAD_SIGNAL(player); + MMPLAYER_BUS_MSG_THREAD_UNLOCK(player); + + LOGD("gst bus msg thread exit."); + g_thread_join(player->bus_msg_thread); + player->bus_msg_thread = NULL; + + g_mutex_clear(&player->bus_msg_thread_mutex); + g_cond_clear(&player->bus_msg_thread_cond); + } + + MMPLAYER_FLEAVE(); +} + +static gpointer __mmplayer_gst_bus_msg_thread(gpointer data) +{ + mm_player_t *player = (mm_player_t*)(data); + GstMessage *msg = NULL; + GstBus *bus = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && + player->pipeline && + player->pipeline->mainbin && + player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, + NULL); + + bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); + if (!bus) { + LOGE("cannot get BUS from the pipeline"); + return NULL; + } + + MMPLAYER_BUS_MSG_THREAD_LOCK(player); + + LOGD("gst bus msg thread will be started."); + while (!player->bus_msg_thread_exit) { + msg = gst_bus_pop(bus); + if (msg == NULL) { + /* set the max timeout as 500 ms */ + MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + 500 * G_TIME_SPAN_MILLISECOND)); + continue; + } + + MMPLAYER_BUS_MSG_THREAD_UNLOCK(player); + /* handle the gst msg */ + __mmplayer_gst_callback(msg, player); + MMPLAYER_BUS_MSG_THREAD_LOCK(player); + gst_message_unref(msg); + } + + MMPLAYER_BUS_MSG_THREAD_UNLOCK(player); + gst_object_unref(GST_OBJECT(bus)); + + MMPLAYER_FLEAVE(); + return NULL; +} + +static void +__mmplayer_gst_callback(GstMessage *msg, gpointer data) +{ + mm_player_t* player = (mm_player_t*)(data); static gboolean async_done = FALSE; - MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); - MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE); + MMPLAYER_RETURN_IF_FAIL(player); + MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg)); switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_UNKNOWN: @@ -1305,11 +1373,6 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ } } else { MMPLAYER_CMD_LOCK(player); - if (!player->pipeline) { /* during destroy, msg can be delivered. */ - LOGE("pipeline is destroyed."); - MMPLAYER_CMD_UNLOCK(player); - break; - } } /* ignore the prev buffering message */ @@ -1556,7 +1619,6 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ attrs = MMPLAYER_GET_ATTRS(player); if (!attrs) { LOGE("cannot get content attribute"); - ret = FALSE; break; } @@ -1677,8 +1739,7 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ case GST_MESSAGE_DURATION_CHANGED: { LOGD("GST_MESSAGE_DURATION_CHANGED\n"); - ret = __mmplayer_gst_handle_duration(player, msg); - if (!ret) + if (!__mmplayer_gst_handle_duration(player, msg)) LOGW("failed to update duration"); } @@ -1753,12 +1814,8 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ break; } - /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since - * gst_element_post_message api takes ownership of the message. - */ - //gst_message_unref(msg); - - return ret; + /* should not call 'gst_message_unref(msg)' */ + return; } static gboolean @@ -5991,7 +6048,7 @@ __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_STATE_CHANGED: /* post directly for fast launch */ if (player->sync_handler) { - __mmplayer_gst_callback(NULL, message, player); + __mmplayer_gst_callback(message, player); reply = GST_BUS_DROP; } else reply = GST_BUS_PASS; @@ -6751,6 +6808,12 @@ __mmplayer_gst_create_pipeline(mm_player_t* player) // @ __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps); } + /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */ + if (__mmplayer_check_subtitle(player)) { + if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player)) + LOGE("fail to create text pipeline"); + } + /* connect bus callback */ bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst)); if (!bus) { @@ -6758,22 +6821,6 @@ __mmplayer_gst_create_pipeline(mm_player_t* player) // @ goto INIT_ERROR; } - player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player); - - player->context.thread_default = g_main_context_get_thread_default(); - - if (NULL == player->context.thread_default) { - player->context.thread_default = g_main_context_default(); - LOGD("thread-default context is the global default context"); - } - LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher); - - /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */ - if (__mmplayer_check_subtitle(player)) { - if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player)) - LOGE("fail to create subtitle src\n"); - } - /* set sync handler to get tag synchronously */ gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL); @@ -6781,6 +6828,19 @@ __mmplayer_gst_create_pipeline(mm_player_t* player) // @ gst_object_unref(GST_OBJECT(bus)); g_list_free(element_bucket); + /* create gst bus_msb_cb thread */ + g_mutex_init(&player->bus_msg_thread_mutex); + g_cond_init(&player->bus_msg_thread_cond); + player->bus_msg_thread_exit = FALSE; + player->bus_msg_thread = + g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL); + if (!player->bus_msg_thread) { + LOGE("failed to create gst BUS msg thread"); + g_mutex_clear(&player->bus_msg_thread_mutex); + g_cond_clear(&player->bus_msg_thread_cond); + goto INIT_ERROR; + } + MMPLAYER_FLEAVE(); return MM_ERROR_NONE; @@ -6878,11 +6938,6 @@ __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @ /* first we need to disconnect all signal hander */ __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL); - /* disconnecting bus watch */ - if (player->bus_watcher) - __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher); - player->bus_watcher = 0; - if (mainbin) { MMPlayerGstElement* audiobin = player->pipeline->audiobin; MMPlayerGstElement* videobin = player->pipeline->videobin; @@ -8221,9 +8276,10 @@ void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_t } __mmplayer_undo_sound_fadedown(player); - } else + } else { /* rtsp should connect again in specific network becasue tcp session can't be kept any more */ _mmplayer_unrealize((MMHandleType)player); + } } else { LOGW("pause immediately"); result = _mmplayer_pause((MMHandleType)player); @@ -9014,7 +9070,13 @@ _mmplayer_unrealize(MMHandleType hplayer) MMPLAYER_FENTER(); - MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED) + MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); + + MMPLAYER_CMD_UNLOCK(player); + /* destroy the gst bus msg thread which is created during realize. + this funct have to be called before getting cmd lock. */ + _mmplayer_bus_msg_thread_destroy(player); + MMPLAYER_CMD_LOCK(player); /* check current state */ MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE); @@ -13250,8 +13312,8 @@ __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms) player->eos_timer = g_timeout_add(delay_in_ms, __mmplayer_eos_timer_cb, player); - player->context.global_default = g_main_context_default(); - LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer); + player->global_default = g_main_context_default(); + LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer); /* check timer is valid. if not, send EOS now */ if (player->eos_timer == 0) { @@ -13267,7 +13329,7 @@ __mmplayer_cancel_eos_timer(mm_player_t* player) if (player->eos_timer) { LOGD("cancel eos timer"); - __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer); + __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer); player->eos_timer = 0; } @@ -14255,9 +14317,11 @@ int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filep LOGE("fail to create subtitle src\n"); result = _mmplayer_sync_subtitle_pipeline(player); - } else + } else { result = __mmplayer_change_external_subtitle_language(player, filepath); + } + MMPLAYER_BUS_MSG_THREAD_SIGNAL(player); player->is_external_subtitle_added_now = TRUE; }