From: Eunhae Choi Date: Thu, 26 Jul 2018 11:43:29 +0000 (+0900) Subject: [0.6.120] support force resume during buffering by seeking X-Git-Tag: submit/tizen/20180730.025527^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=30442f6a1d3c05eaca2b31c7431216d03ca81fcd;p=platform%2Fcore%2Fmultimedia%2Flibmm-player.git [0.6.120] support force resume during buffering by seeking - change the seek complete scheme - sync the decodebin state with player after seeking - restore the rtsp pending seek path Change-Id: Ie0fe1ff7087b0b4fd782f1e93e074d15791ca79f --- diff --git a/packaging/libmm-player.spec b/packaging/libmm-player.spec index e9308fd..cbfc9b6 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.119 +Version: 0.6.120 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 64e879b..b62b312 100644 --- a/src/include/mm_player_priv.h +++ b/src/include/mm_player_priv.h @@ -334,6 +334,12 @@ enum StreamingSrcError { MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED, }; +typedef enum { + MMPLAYER_SEEK_NONE = 0, + MMPLAYER_SEEK_IN_PROGRESS, + MMPLAYER_SEEK_COMPLETED, /* after getting async done but before posting seek complete */ +} MMPlayerSeekState; + typedef enum { MMPLAYER_PATH_VOD = 0, MMPLAYER_PATH_TEXT, @@ -718,8 +724,7 @@ typedef struct { /* support seek even though player is not start */ MMPlayerPendingSeek pending_seek; - - gboolean doing_seek; + MMPlayerSeekState seek_state; /* prevent to post msg over and over */ gboolean msg_posted; diff --git a/src/mm_player_common_priv.c b/src/mm_player_common_priv.c index 4003a5d..a9957e7 100644 --- a/src/mm_player_common_priv.c +++ b/src/mm_player_common_priv.c @@ -181,7 +181,7 @@ __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command) if (MMPLAYER_IS_LIVE_STREAMING(player)) goto NO_OP; - if (player->doing_seek) + if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) goto NOT_COMPLETED_SEEK; MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; @@ -204,8 +204,7 @@ __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command) case MMPLAYER_COMMAND_RESUME: { - - if (player->doing_seek) + if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) goto NOT_COMPLETED_SEEK; MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING; diff --git a/src/mm_player_priv.c b/src/mm_player_priv.c index f11b2b3..99d61c2 100644 --- a/src/mm_player_priv.c +++ b/src/mm_player_priv.c @@ -1059,7 +1059,6 @@ static void __mmplayer_gst_callback(GstMessage *msg, gpointer data) { mm_player_t* player = (mm_player_t*)(data); - static gboolean async_done = FALSE; MMPLAYER_RETURN_IF_FAIL(player); MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg)); @@ -1262,16 +1261,16 @@ __mmplayer_gst_callback(GstMessage *msg, gpointer data) gst_message_parse_buffering(msg, &buffer_percent); - LOGD("force resume -last posted %d %%, new per %d %%", + LOGD("interrupted buffering -last posted %d %%, new per %d %%", player->streamer->buffering_percent, buffer_percent); - if (player->streamer->buffering_percent > buffer_percent) { + if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) { player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT; player->streamer->buffering_req.is_pre_buffering = FALSE; - LOGD("force resume - need to enter the buffering mode again - %d %%", buffer_percent); + LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent); } else { - LOGD("force resume - ignored the remained buffering msg!"); + LOGD("interrupted buffering - ignored the remained buffering msg!"); MMPLAYER_CMD_UNLOCK(player); break; } @@ -1297,12 +1296,14 @@ __mmplayer_gst_callback(GstMessage *msg, gpointer data) if (MMPLAYER_IS_RTSP_STREAMING(player) && (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) { - if (player->doing_seek) { + if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) { if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) { - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) { - async_done = TRUE; + /* Considering the async state trasition in case of RTSP. + After getting state change gst msg, seek cmpleted msg will be posted. */ + player->seek_state = MMPLAYER_SEEK_COMPLETED; } } } @@ -1461,9 +1462,8 @@ __mmplayer_gst_callback(GstMessage *msg, gpointer data) player->gapless.stream_changed = FALSE; } - if (player->doing_seek && async_done) { - player->doing_seek = FALSE; - async_done = FALSE; + if (player->seek_state == MMPLAYER_SEEK_COMPLETED) { + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); } } @@ -1677,17 +1677,39 @@ __mmplayer_gst_callback(GstMessage *msg, gpointer data) case GST_MESSAGE_ASYNC_DONE: { + MMPlayerGstElement *mainbin; + + if (!(player->pipeline && player->pipeline->mainbin)) { + LOGE("player pipeline handle is null"); + break; + } + + mainbin = player->pipeline->mainbin; + LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); /* we only handle messages from pipeline */ - if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) + if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst) break; - if (player->doing_seek) { + if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) { if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) { - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) { + if (mainbin[MMPLAYER_M_AUTOPLUG].gst) { + LOGD("sync %s state(%s) with parent state(%s)", + GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst), + gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)), + gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst))); + + /* In case of streaming, pause is required before finishing seeking by buffering. + After completing the seek(during buffering), the player and sink elems has paused state but others in playing state. + Because the buffering state is controlled according to the state transition for force resume, + the decodebin state should be paused as player state. */ + gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst); + } + if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (player->streamer) && (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) && @@ -1710,7 +1732,7 @@ __mmplayer_gst_callback(GstMessage *msg, gpointer data) __mmplayer_handle_buffering_message(player); } - async_done = TRUE; + player->seek_state = MMPLAYER_SEEK_COMPLETED; } } } @@ -6764,7 +6786,6 @@ __mmplayer_gst_create_pipeline(mm_player_t* player) G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player); } - /* check autoplug element is OK */ if (!element) { LOGE("can not create element(%d)\n", elemId); @@ -7485,7 +7506,7 @@ __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean in player->pending_seek.is_pending = TRUE; player->pending_seek.format = format; player->pending_seek.pos = position; - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); return MM_ERROR_NONE; } else { @@ -7522,7 +7543,7 @@ __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean in if (!seekable) { LOGW("non-seekable content"); - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; return MM_ERROR_PLAYER_NO_OP; } } else { @@ -7545,14 +7566,14 @@ __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean in g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL); } - if (player->doing_seek) { + if (player->seek_state != MMPLAYER_SEEK_NONE) { LOGD("not completed seek"); return MM_ERROR_PLAYER_DOING_SEEK; } } if (!internal_called) - player->doing_seek = TRUE; + player->seek_state = MMPLAYER_SEEK_IN_PROGRESS; if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) { gint64 cur_time = 0; @@ -7585,7 +7606,7 @@ __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean in g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL); LOGD("[%s] set position =%"GST_TIME_FORMAT, GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec)); - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); } else { ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, @@ -7604,13 +7625,13 @@ __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean in { LOGD("seeking to %"G_GINT64_FORMAT"%%", position); - if (player->doing_seek) { + if (player->seek_state != MMPLAYER_SEEK_NONE) { LOGD("not completed seek"); return MM_ERROR_PLAYER_DOING_SEEK; } if (!internal_called) - player->doing_seek = TRUE; + player->seek_state = MMPLAYER_SEEK_IN_PROGRESS; /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */ pos_nsec = (gint64)((position * player->duration) / 100); @@ -7637,6 +7658,13 @@ __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean in if (player->playback_rate > 1.0) _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE); + if ((!internal_called) && + (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) { + LOGD("buffering should be reset after seeking"); + player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT; + player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */ + } + MMPLAYER_FLEAVE(); return MM_ERROR_NONE; @@ -7657,7 +7685,7 @@ INVALID_ARGS: return MM_ERROR_INVALID_ARGUMENT; SEEK_ERROR: - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; return MM_ERROR_PLAYER_SEEK; } @@ -8086,11 +8114,11 @@ __mmplayer_can_do_interrupt(mm_player_t *player) } /* check if seeking */ - if (player->doing_seek) { + if (player->seek_state != MMPLAYER_SEEK_NONE) { MMMessageParamType msg_param; memset(&msg_param, 0, sizeof(MMMessageParamType)); msg_param.code = MM_ERROR_PLAYER_SEEK; - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); goto FAILED; } @@ -9234,7 +9262,7 @@ _mmplayer_stop(MMHandleType hplayer) __mmplayer_unrealize_streaming_ext(player); /* reset */ - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; /* stop pipeline */ ret = __gst_stop(player); @@ -9337,8 +9365,13 @@ _mmplayer_resume(MMHandleType hplayer) MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* Changing back sync mode rtspsrc to async */ if ((MMPLAYER_IS_RTSP_STREAMING(player))) { + if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */ + player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */ + return ret; + } + + /* Changing back sync mode rtspsrc to async */ LOGD("async resume for rtsp case"); async = TRUE; } @@ -9346,16 +9379,15 @@ _mmplayer_resume(MMHandleType hplayer) /* check current state */ MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME); + ret = __gst_resume(player, async); + if (ret != MM_ERROR_NONE) + LOGE("failed to resume player.\n"); + if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) { LOGD("force resume even during buffering"); player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT; } - ret = __gst_resume(player, async); - - if (ret != MM_ERROR_NONE) - LOGE("failed to resume player.\n"); - MMPLAYER_FLEAVE(); return ret; @@ -10240,7 +10272,7 @@ __mmplayer_initialize_next_play(mm_player_t *player) player->has_many_types = FALSE; player->no_more_pad = FALSE; player->not_found_demuxer = 0; - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; player->max_audio_channels = 0; player->is_subtitle_force_drop = FALSE; player->play_subtitle = FALSE; @@ -11328,7 +11360,7 @@ __mmplayer_release_misc(mm_player_t* player) player->sent_bos = FALSE; player->playback_rate = DEFAULT_PLAYBACK_RATE; - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; player->total_bitrate = 0; player->total_maximum_bitrate = 0; @@ -11885,7 +11917,7 @@ __gst_send_event_to_sink(mm_player_t* player, GstEvent* event) if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) { if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) { LOGD("RTSP seek completed, after pause state..\n"); - player->doing_seek = FALSE; + player->seek_state = MMPLAYER_SEEK_NONE; MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL); } @@ -12201,7 +12233,7 @@ __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const c return MM_ERROR_PLAYER_INTERNAL; } - if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) { + if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) { LOGW("trying to block pad(video)"); // if (!gst_pad_set_blocked(src_pad_dec, TRUE)) gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, @@ -12213,8 +12245,8 @@ __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const c LOGW("pad is blocked(video)"); } else { /* no data flows, so no need to do pad_block */ - if (player->doing_seek) - LOGW("not completed seek(%d), do nothing", player->doing_seek); + if (player->seek_state != MMPLAYER_SEEK_NONE) + LOGW("not completed seek(%d), do nothing", player->seek_state); LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)"); } @@ -12351,7 +12383,7 @@ __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const c } else LOGW("failed to get clock, maybe it is the time before first playing"); - if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) { + if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) { /* change state of videobin to PAUSED */ LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING); ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING); @@ -12371,8 +12403,8 @@ __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const c #endif LOGW("pad is unblocked(video)"); } else { - if (player->doing_seek) - LOGW("not completed seek(%d)", player->doing_seek); + if (player->seek_state != MMPLAYER_SEEK_NONE) + LOGW("not completed seek(%d)", player->seek_state); /* change state of videobin to PAUSED */ LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED); ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED); @@ -12982,7 +13014,7 @@ _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint6 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT, clock, clock_delta, video_time, media_clock, audio_time); */ - if ((video_time < 0) || (player->doing_seek)) { + if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) { LOGD("skip setting master clock. %lld", video_time); goto EXIT; }