[0.6.120] support force resume during buffering by seeking 70/185170/1 accepted/tizen/unified/20180801.144912 submit/tizen/20180730.025527
authorEunhae Choi <eunhae1.choi@samsung.com>
Thu, 26 Jul 2018 11:43:29 +0000 (20:43 +0900)
committerEunhae Choi <eunhae1.choi@samsung.com>
Thu, 26 Jul 2018 11:43:34 +0000 (20:43 +0900)
- change the seek complete scheme
- sync the decodebin state with player after seeking
- restore the rtsp pending seek path

Change-Id: Ie0fe1ff7087b0b4fd782f1e93e074d15791ca79f

packaging/libmm-player.spec
src/include/mm_player_priv.h
src/mm_player_common_priv.c
src/mm_player_priv.c

index e9308fd..cbfc9b6 100644 (file)
@@ -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
index 64e879b..b62b312 100644 (file)
@@ -335,6 +335,12 @@ enum StreamingSrcError {
 };
 
 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,
        MMPLAYER_PATH_MAX
@@ -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;
index 4003a5d..a9957e7 100644 (file)
@@ -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;
index f11b2b3..99d61c2 100644 (file)
@@ -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;
        }