Implemented Mediastreamer Seek function set_play_position() API 20/49220/1
authorVyacheslav Valkovoy <v.valkovoy@samsung.com>
Thu, 8 Oct 2015 14:40:10 +0000 (17:40 +0300)
committerVyacheslav Valkovoy <v.valkovoy@samsung.com>
Thu, 8 Oct 2015 14:40:10 +0000 (17:40 +0300)
Change-Id: I02863a00df706ed24d79a47f8efc48dc64d2fec8
Signed-off-by: Vyacheslav Valkovoy <v.valkovoy@samsung.com>
include/media_streamer.h
include/media_streamer_priv.h
src/media_streamer.c
src/media_streamer_gst.c
src/media_streamer_priv.c
test/media_streamer_test.c

index a5ac441..9619533 100644 (file)
@@ -446,7 +446,7 @@ typedef void (*media_streamer_sink_eos_cb)(media_streamer_node_h node,
 /**
  * @brief Called when the seek operation is completed.
  * @since_tizen 3.0
- * @param [in] user_data     The user data passed from the callback registration function
+ * @param[in] user_data     The user data passed from the callback registration function
  * @see media_streamer_set_play_position()
  */
 typedef void (*media_streamer_position_changed_cb)(void *user_data);
@@ -793,6 +793,7 @@ int media_streamer_set_play_position(media_streamer_h streamer,
                                      bool accurate,
                                      media_streamer_position_changed_cb callback,
                                      void *user_data);
+
 /**
  * @brief Gets the current position in milliseconds.
  * @since_tizen 3.0
index 305ba87..6c1ed3b 100755 (executable)
@@ -71,11 +71,13 @@ typedef struct {
 
        GstBus *bus;
        guint bus_watcher;
+       gboolean is_seeking;
 
        media_streamer_state_e state;
 
        media_streamer_callback_s error_cb;
        media_streamer_callback_s state_changed_cb;
+       media_streamer_callback_s seek_done_cb;
 } media_streamer_s;
 
 /**
@@ -106,6 +108,13 @@ typedef struct {
 /* Private functions definition */
 
 /**
+ * @brief Seeks Media streamer element to the pointed position.
+ *
+ * @since_tizen 3.0
+ */
+int __ms_streamer_seek(media_streamer_s *ms_streamer, int time, bool flag);
+
+/**
  * @brief Destroys media streamer structure.
  *
  * @since_tizen 3.0
index 7cba347..c212b40 100755 (executable)
@@ -515,6 +515,44 @@ int media_streamer_get_state(media_streamer_h streamer,
        return MEDIA_STREAMER_ERROR_NONE;
 }
 
+int media_streamer_set_play_position(media_streamer_h streamer,
+                                     int time,
+                                     bool accurate,
+                                    media_streamer_position_changed_cb callback,
+                                     void *user_data)
+{
+       media_streamer_s *ms_streamer = (media_streamer_s *)streamer;
+       ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
+
+       ms_retvm_if(ms_streamer->state < MEDIA_STREAMER_STATE_READY ||
+                ms_streamer->state > MEDIA_STREAMER_STATE_PAUSED,
+                MEDIA_STREAMER_ERROR_INVALID_STATE,
+                "The media streamer state is not in the appropriate state");
+
+       /* Notify: the seeking must be reseted while streamer got ASYNC_DONE message */
+       ms_retvm_if(ms_streamer->is_seeking, MEDIA_STREAMER_ERROR_INVALID_STATE, "Media streamer is seeking");
+
+       int ret = MEDIA_STREAMER_ERROR_NONE;
+       g_mutex_lock(&ms_streamer->mutex_lock);
+
+       ms_streamer->seek_done_cb.callback = callback;
+       ms_streamer->seek_done_cb.user_data = user_data;
+
+       ret = __ms_streamer_seek(streamer, time, accurate);
+
+       g_mutex_unlock(&ms_streamer->mutex_lock);
+
+       return ret;
+}
+
+int media_streamer_get_play_position(media_streamer_h streamer, int *time)
+{
+       media_streamer_s *ms_streamer = (media_streamer_s *)streamer;
+       ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
+
+       return MEDIA_STREAMER_ERROR_NONE;
+}
+
 int media_streamer_node_push_packet(media_streamer_node_h src,
                                media_packet_h packet)
 {
index a6132d5..97642fc 100755 (executable)
@@ -1482,6 +1482,21 @@ static gboolean __ms_bus_cb(GstBus *bus, GstMessage *message, gpointer userdata)
                                        break;
                                }
 
+                       case GST_MESSAGE_ASYNC_DONE: {
+                               if (GST_MESSAGE_SRC(message) == GST_OBJECT(ms_streamer->pipeline)
+                                    && ms_streamer->is_seeking) {
+
+                                       if (ms_streamer->seek_done_cb.callback) {
+                                               media_streamer_position_changed_cb cb = (media_streamer_position_changed_cb) ms_streamer->seek_done_cb.callback;
+                                               cb(ms_streamer->seek_done_cb.user_data);
+                                       }
+
+                                       ms_streamer->is_seeking = FALSE;
+                                       ms_streamer->seek_done_cb.callback = NULL;
+                                       ms_streamer->seek_done_cb.user_data = NULL;
+                               }
+                               break;
+                       }
                        case GST_MESSAGE_EOS: {
                                        ms_info("GST_MESSAGE_EOS end-of-stream");
                                        ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED);
@@ -1780,6 +1795,23 @@ int __ms_element_set_fmt(media_streamer_node_s *node, const char *pad_name, medi
        return MEDIA_STREAMER_ERROR_NONE;
 }
 
+gboolean __ms_gst_seek(GstElement *element, gint64 g_time, GstSeekFlags seek_flag)
+{
+       gboolean result = FALSE;
+
+       ms_retvm_if(element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Element is NULL");
+
+       GstEvent *event = gst_event_new_seek(1.0, GST_FORMAT_TIME, seek_flag,
+                                            GST_SEEK_TYPE_SET, g_time,
+                                            GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+       if (event) {
+               result = gst_element_send_event(element, event);
+       }
+
+       return result;
+}
+
 int __ms_element_push_packet(GstElement *src_element, media_packet_h packet)
 {
        GstBuffer *buffer = NULL;
index e5e9271..e70f271 100755 (executable)
@@ -141,6 +141,30 @@ static void __node_remove_cb(gpointer key,
 }
 #endif
 
+int __ms_streamer_seek(media_streamer_s *ms_streamer, int g_time, bool flag)
+{
+       ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
+
+       GstSeekFlags seek_flag;
+
+       if (flag) {
+               seek_flag = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE;
+       } else {
+               seek_flag = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT;
+       }
+
+       if (!__ms_gst_seek(ms_streamer->pipeline, (gint64)g_time*GST_MSECOND, seek_flag)) {
+               ms_error("Error while seeking media streamer to [%d]\n", g_time);
+               return MEDIA_STREAMER_ERROR_SEEK_FAILED;
+       } else {
+               ms_streamer->is_seeking = TRUE;
+       }
+
+       ms_info("Media streamer pipeline seeked successfully.");
+
+       return MEDIA_STREAMER_ERROR_NONE;
+}
+
 void __ms_streamer_destroy(media_streamer_s *ms_streamer)
 {
        if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_NONE) != MEDIA_STREAMER_ERROR_NONE) {
index 48c16f6..6099990 100755 (executable)
@@ -35,6 +35,7 @@ typedef enum {
 typedef enum {
        SUBMENU_STATE_UNKNOWN,
        SUBMENU_STATE_GETTING_IP,
+       SUBMENU_STATE_GETTING_SEEK_POS,
        SUBMENU_STATE_GETTING_VIDEOFILE_URI,
        SUBMENU_STATE_GETTING_SUBFILE_URI,
        SUBMENU_STATE_AUTOPLUG,
@@ -67,35 +68,38 @@ typedef enum
        SCENARIO_MODE_VIDEOTEST_SCREEN,
        SCENARIO_MODE_AUDIOTEST_PHONE,
        SCENARIO_MODE_TEST_VIDEO_AUDIO,
-       SCENARIO_MODE_FILE_VIDEO_AUDIO,
+       SCENARIO_MODE_FILE_PLAY_VIDEO_AUDIO,
        SCENARIO_MODE_FILE_SUBTITLE_VIDEO_AUDIO,
        SCENARIO_MODE_HTTP_VIDEO_AUDIO,
        SCENARIO_MODE_APPSRC_APPSINK
 } scenario_mode_e;
 
 #define PACKAGE "media_streamer_test"
-/*---------------------------------------------------------------------------
-|    GLOBAL VARIABLE DEFINITIONS:                     |
----------------------------------------------------------------------------*/
-
-static media_streamer_h g_media_streamer;
-static media_streamer_h g_media_streamer_2;
-static media_streamer_h current_media_streamer = &g_media_streamer;
 
 #define MAX_STRING_LEN    2048
-#define DEFAULT_IP_ADDR "127.0.0.1"
+#define DEFAULT_IP_ADDR   "127.0.0.1"
+#define DEFAULT_SEEK_POS   0
+#define MSEC_MULTIPLIER   1000
+
 
 #define VIDEO_PORT 5000
 #define AUDIO_PORT 6000
 
 /*---------------------------------------------------------------------------
-|    LOCAL VARIABLE DEFINITIONS:                      |
+|    GLOBAL VARIABLE DEFINITIONS:                     |
 ---------------------------------------------------------------------------*/
+
+static media_streamer_h g_media_streamer;
+static media_streamer_h g_media_streamer_2;
+static media_streamer_h current_media_streamer = &g_media_streamer;
 GMainLoop *g_loop;
 
 gchar *g_broadcast_address = NULL;
+int g_seek_pos = 0;
+int g_time = 0;
 gchar *g_uri = NULL;
 gchar *g_sub_uri = NULL;
+
 menu_state_e g_menu_state = MENU_STATE_MAIN_MENU;
 submenu_state_e g_sub_menu_state = SUBMENU_STATE_UNKNOWN;
 preset_type_e g_menu_preset = PRESET_UNKNOWN;
@@ -109,10 +113,6 @@ media_format_h vfmt_raw = NULL;
 media_format_h vfmt_encoded = NULL;
 media_format_h afmt_raw = NULL;
 
-/*---------------------------------------------------------------------------
-|    LOCAL FUNCTION PROTOTYPES:                       |
----------------------------------------------------------------------------*/
-
 static void streamer_error_cb(media_streamer_h streamer,
                               media_streamer_error_e error,
                               void *user_data)
@@ -120,6 +120,10 @@ static void streamer_error_cb(media_streamer_h streamer,
        g_print("Media Streamer posted error [%d] \n", error);
 }
 
+static void streamer_seek_cb(void *user_data) {
+       g_print("Media Streamer seeked to required position \n");
+}
+
 static void _create(media_streamer_h *streamer)
 {
        g_print("== create \n");
@@ -191,6 +195,21 @@ static void _pause()
        g_print("== success pause \n");
 }
 
+static void _seek()
+{
+       g_print("== seek \n");
+       int ret = MEDIA_STREAMER_ERROR_NONE;
+
+       ret = media_streamer_set_play_position(current_media_streamer, g_time, TRUE,
+                                           streamer_seek_cb, current_media_streamer);
+
+       if (ret != MEDIA_STREAMER_ERROR_NONE) {
+               g_print("Fail to seek media streamer");
+               return;
+       }
+       g_print("== success seek \n");
+}
+
 static void _stop()
 {
        g_print("== stop \n");
@@ -314,7 +333,6 @@ static void set_rtp_params(media_streamer_node_h rtp_node,
        media_streamer_node_set_pad_format(rtp_node, "audio_in_rtp", afmt_raw);
 
        bundle_free(params);
-       params = NULL;
 }
 
 static void _create_file_playing()
@@ -700,6 +718,13 @@ static void display_getting_sub_uri_menu(void)
        g_print("Please input Subtitle path for playing\n");
 }
 
+static void display_getting_seek_position_menu(void)
+{
+       g_print("\n");
+       g_print("Please enter desired position\n");
+       g_print("By default will be seeked to [%d]\n", DEFAULT_SEEK_POS);
+}
+
 static void display_autoplug_select_menu(void)
 {
        g_print("\n");
@@ -721,7 +746,6 @@ static void display_scenario_select_menu(void)
        g_print("4. Video test -> Screen\n");
        g_print("5. Audio test -> Phones\n");
        g_print("6. Video test + Audio test -> Screen + Phones\n");
-
 }
 
 static void display_playing_scenario_select_menu(void)
@@ -750,10 +774,11 @@ static void display_preset_menu(void)
        g_print("----------------------------------------------------\n");
        g_print("1. create media streamer \n");
        g_print("2. set up current preset \n");
-       g_print("4. prepare \n");
-       g_print("5. unprepare \n");
-       g_print("6. play \n");
-       g_print("7. pause \n");
+       g_print("3. prepare \n");
+       g_print("4. unprepare \n");
+       g_print("5. play \n");
+       g_print("6. pause \n");
+       g_print("7. seek \n");
        g_print("8. stop \n");
        g_print("9. destroy media streamer \n\n");
        g_print("b. back \n");
@@ -833,6 +858,9 @@ static void display_menu(void)
                        case SUBMENU_STATE_GETTING_IP:
                                display_getting_ip_menu();
                                break;
+                       case SUBMENU_STATE_GETTING_SEEK_POS:
+                               display_getting_seek_position_menu();
+                               break;
                        case SUBMENU_STATE_GETTING_VIDEOFILE_URI:
                                display_getting_uri_menu();
                                break;
@@ -916,7 +944,7 @@ void run_playing_preset(void)
 {
        create_formats();
 
-       if (g_scenario_mode == SCENARIO_MODE_FILE_VIDEO_AUDIO) {
+       if (g_scenario_mode == SCENARIO_MODE_FILE_PLAY_VIDEO_AUDIO) {
                _create_file_playing();
        } else if (g_scenario_mode == SCENARIO_MODE_FILE_SUBTITLE_VIDEO_AUDIO) {
                _create_file_sub_playing();
@@ -1011,7 +1039,7 @@ void _interpret_playing_scenario_menu(char *cmd)
 
        if (len == 1) {
                if (!strncmp(cmd, "1", len)) {
-                       g_scenario_mode = SCENARIO_MODE_FILE_VIDEO_AUDIO;
+                       g_scenario_mode = SCENARIO_MODE_FILE_PLAY_VIDEO_AUDIO;
                        g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI;
                        return;
                } else if (!strncmp(cmd, "2", len)) {
@@ -1085,6 +1113,21 @@ void _interpret_getting_ip_menu(char *cmd)
        g_sub_menu_state = SUBMENU_STATE_SCENARIO;
 }
 
+void _interpret_getting_seek_position_menu(char *cmd)
+{
+       if (cmd > DEFAULT_SEEK_POS) {
+               g_time = strtol(cmd, NULL, 10) * MSEC_MULTIPLIER;
+               g_print("== Seek position set to [%d] second\n", g_time);
+       } else {
+               g_time = DEFAULT_SEEK_POS;
+               g_print("Invalid seek pos. Default seek position will be used [%d]\n", DEFAULT_SEEK_POS);
+               return;
+       }
+       _seek();
+
+       g_sub_menu_state = SUBMENU_STATE_UNKNOWN;
+}
+
 void _interpret_getting_sub_uri_menu(char *cmd)
 {
        if (cmd) {
@@ -1176,14 +1219,16 @@ void _interpret_preset_menu(char *cmd)
                        } else {
                                g_sub_menu_state = SUBMENU_STATE_AUTOPLUG;
                        }
-               } else if (!strncmp(cmd, "4", len)) {
+               } else if (!strncmp(cmd, "3", len)) {
                        _prepare();
-               } else if (!strncmp(cmd, "5", len)) {
+               } else if (!strncmp(cmd, "4", len)) {
                        _unprepare();
-               } else if (!strncmp(cmd, "6", len)) {
+               } else if (!strncmp(cmd, "5", len)) {
                        _play();
-               } else if (!strncmp(cmd, "7", len)) {
+               } else if (!strncmp(cmd, "6", len)) {
                        _pause();
+               } else if (!strncmp(cmd, "7", len)) {
+                       g_sub_menu_state = SUBMENU_STATE_GETTING_SEEK_POS;
                } else if (!strncmp(cmd, "8", len)) {
                        _stop();
                } else if (!strncmp(cmd, "9", len)) {
@@ -1234,6 +1279,9 @@ static void interpret_cmd(char *cmd)
                        case SUBMENU_STATE_GETTING_IP:
                                _interpret_getting_ip_menu(cmd);
                                break;
+                       case SUBMENU_STATE_GETTING_SEEK_POS:
+                               _interpret_getting_seek_position_menu(cmd);
+                               break;
                        case SUBMENU_STATE_GETTING_VIDEOFILE_URI:
                                _interpret_getting_uri_menu(cmd);
                                break;