Fix some issues during test 20/301920/5
authorYoungwoo Cho <young222.cho@samsung.com>
Mon, 27 Nov 2023 08:57:26 +0000 (17:57 +0900)
committerYoungwoo Cho <young222.cho@samsung.com>
Wed, 29 Nov 2023 05:53:34 +0000 (14:53 +0900)
- fix freezing error during seek
 : old packet is submitted
 : when overrun is signaled, underrun is not signaled because media is paused during seek
    so using g_cond_wait_until, continuously inserting packets
 : sometimes process is blocked in mediademuxer_read_sample() because of gst_app_sink_pull_sample()
    so split demuxer into audio and video demuxers
- fix crashing error during quit program(deinit)
 : when some stream is stopped, other stream is blocked in mediademuxer_read_sample during waiting for full
    so unselect track to stop appsink

Change-Id: I951bf0cae97735a1191adb4bd7eba2a267eb4707
Signed-off-by: Youngwoo Cho <young222.cho@samsung.com>
test/esplusplayer_test.cpp

index 1df7aef..3fa200f 100644 (file)
@@ -39,7 +39,7 @@
 
 #define MAX_STRING_LEN 2048
 #define MAX_TRACK_COUNT        10
-
+constexpr uint64_t SEEK_WAIT_TIME = 100 * G_TIME_SPAN_MILLISECOND;
 // #define DEBUG_LOG
 
 enum {
@@ -48,6 +48,7 @@ enum {
        CURRENT_STATUS_ACTIVATE,
        CURRENT_STATUS_DEACTIVATE,
        CURRENT_STATUS_SEEK,
+       CURRENT_STATUS_SET_SEEK_RANGE,
        CURRENT_STATUS_SET_RATE,
        CURRENT_STATUS_SET_VOLUME,
        CURRENT_STATUS_SET_MUTE,
@@ -88,12 +89,15 @@ typedef struct {
        media_packet_h pending_packet;
        GMutex mutex;
        GCond cond;
-       bool wait_thread;
        pthread_t thread;
+       bool wait_thread;
+       bool is_seek_queue_flushing;
+       bool is_full_waiting;
 } stream_t;
 
 typedef struct {
-       mediademuxer_h demux_h;
+       mediademuxer_h audio_demux_h;
+       mediademuxer_h video_demux_h;
        esplusplayer_handle espp_h;
        int num_tracks;
        stream_t streams[STREAM_MAX];
@@ -102,10 +106,13 @@ typedef struct {
        int video_track_id;
        int audio_track_id;
        sound_stream_info_h stream_info;
+       bool is_seek_done;
 } test_h;
 
 static appdata g_ad;
 static test_h *g_test_h;
+static GRand *g_seek_rand = g_rand_new();
+static int g_max_range = 0;
 
 #define STREAM_LOCK(type) { \
        g_mutex_lock(&g_test_h->streams[type].mutex); \
@@ -116,13 +123,16 @@ static test_h *g_test_h;
 }
 
 #define STREAM_WAIT(type) { \
-       g_cond_wait (&g_test_h->streams[type].cond, &g_test_h->streams[type].mutex); \
+       g_cond_wait(&g_test_h->streams[type].cond, &g_test_h->streams[type].mutex); \
+}
+
+#define STREAM_WAIT_UNTIL(type, time) { \
+       g_cond_wait_until(&g_test_h->streams[type].cond, &g_test_h->streams[type].mutex, g_get_monotonic_time() + time); \
 }
 
 #define STREAM_SIGNAL(type) { \
-       if (g_test_h->streams[type].wait_thread) { \
-               g_cond_signal (&g_test_h->streams[type].cond); \
-       } \
+       g_test_h->streams[type].wait_thread = false; \
+       g_cond_signal(&g_test_h->streams[type].cond); \
 }
 
 static char *g_uri;
@@ -307,9 +317,8 @@ static void __espp_buffer_status_cb(esplusplayer_stream_type type, esplusplayer_
                        type == ESPLUSPLAYER_STREAM_TYPE_AUDIO ? "Audio" : "Video",
                        status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN ? "UNDERRUN": "OVERRUN");
 #endif
-       if (status == ESPLUSPLAYER_BUFFER_STATUS_OVERRUN) {
-               g_test_h->streams[type].wait_thread = true;
-       } else {
+       if (!g_test_h->streams[type].is_seek_queue_flushing
+                       && status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN) {
                STREAM_SIGNAL(type);
        }
 }
@@ -318,7 +327,17 @@ static void __espp_ready_to_seek_cb(esplusplayer_stream_type type, uint64_t time
 {
        g_print("__espp_ready_to_seek_cb(type:%s, time:%" PRIu64 ")\n",
                        type == ESPLUSPLAYER_STREAM_TYPE_AUDIO ? "Audio" : "Video", time);
+
+       STREAM_LOCK(type);
+       g_test_h->streams[type].is_seek_queue_flushing = false;
        STREAM_SIGNAL(type);
+       STREAM_UNLOCK(type);
+}
+
+static void __espp_seek_done_cb(void *user_data)
+{
+       g_print("__espp_seek_done_cb() is called\n");
+       g_test_h->is_seek_done = true;
 }
 
 static void __espp_event_cb(esplusplayer_event_type type, esplusplayer_event_msg msg, void *user_data)
@@ -362,23 +381,41 @@ static void __init_demux()
                return;
        }
 
-       ret = mediademuxer_create(&g_test_h->demux_h);
+       ret = mediademuxer_create(&g_test_h->audio_demux_h);
+       if (ret != MEDIADEMUXER_ERROR_NONE)
+               g_print("                       => failed to mediademuxer_create(audio)\n");
+       else
+               g_print("                       => mediademuxer_create(audio) success\n");
+
+       ret = mediademuxer_create(&g_test_h->video_demux_h);
+       if (ret != MEDIADEMUXER_ERROR_NONE)
+               g_print("                       => failed to mediademuxer_create(video)\n");
+       else
+               g_print("                       => mediademuxer_create(video) success\n");
+
+       ret = mediademuxer_set_error_cb(g_test_h->audio_demux_h, __mediademuxer_err_cb, g_test_h);
        if (ret != MEDIADEMUXER_ERROR_NONE)
-               g_print("                       => failed to mediademuxer_create()\n");
+               g_print("                       => failed to mediademuxer_set_error_cb(audio)\n");
        else
-               g_print("                       => mediademuxer_create() success\n");
+               g_print("                       => mediademuxer_set_error_cb(audio) success\n");
 
-       ret = mediademuxer_set_error_cb(g_test_h->demux_h, __mediademuxer_err_cb, g_test_h);
+       ret = mediademuxer_set_error_cb(g_test_h->video_demux_h, __mediademuxer_err_cb, g_test_h);
        if (ret != MEDIADEMUXER_ERROR_NONE)
-               g_print("                       => failed to mediademuxer_set_error_cb()\n");
+               g_print("                       => failed to mediademuxer_set_error_cb(video)\n");
        else
-               g_print("                       => mediademuxer_set_error_cb() success\n");
+               g_print("                       => mediademuxer_set_error_cb(video) success\n");
 
-       ret = mediademuxer_set_eos_cb(g_test_h->demux_h, __mediademuxer_eos_cb, g_test_h);
+       ret = mediademuxer_set_eos_cb(g_test_h->audio_demux_h, __mediademuxer_eos_cb, g_test_h);
        if (ret != MEDIADEMUXER_ERROR_NONE)
-               g_print("                       => failed to mediademuxer_set_eos_cb()\n");
+               g_print("                       => failed to mediademuxer_set_eos_cb(audio)\n");
        else
-               g_print("                       => mediademuxer_set_eos_cb() success\n");
+               g_print("                       => mediademuxer_set_eos_cb(audio) success\n");
+
+       ret = mediademuxer_set_eos_cb(g_test_h->video_demux_h, __mediademuxer_eos_cb, g_test_h);
+       if (ret != MEDIADEMUXER_ERROR_NONE)
+               g_print("                       => failed to mediademuxer_set_eos_cb(video)\n");
+       else
+               g_print("                       => mediademuxer_set_eos_cb(video) success\n");
 }
 
 static void __init_espp()
@@ -431,6 +468,12 @@ static void __init_espp()
        else
                g_print("                       => esplusplayer_set_ready_to_seek_cb() success\n");
 
+       ret = esplusplayer_set_seek_done_cb(g_test_h->espp_h, __espp_seek_done_cb, g_test_h);
+       if (ret != ESPLUSPLAYER_ERROR_TYPE_NONE)
+               g_print("                       => failed to esplusplayer_set_seek_done_cb()\n");
+       else
+               g_print("                       => esplusplayer_set_seek_done_cb() success\n");
+
        ret = esplusplayer_set_event_cb(g_test_h->espp_h, __espp_event_cb, g_test_h);
        if (ret != ESPLUSPLAYER_ERROR_TYPE_NONE)
                g_print("                       => failed to esplusplayer_set_event_cb()\n");
@@ -460,6 +503,7 @@ static void __init_test()
        }
        g_test_h->audio_track_id = -1;
        g_test_h->video_track_id = -1;
+       g_test_h->is_seek_done = true;
 
        __init_espp();
        __init_demux();
@@ -467,6 +511,7 @@ static void __init_test()
 
 static void __deinit_test()
 {
+       g_rand_free(g_seek_rand);
        int i = 0;
        if (!g_test_h) {
                g_print("test handle is NULL\n");
@@ -478,10 +523,36 @@ static void __deinit_test()
                g_test_h->stream_info = NULL;
        }
 
+       g_test_h->stop_thread = true;
+
        // need to stop feeding thread;
-       mediademuxer_stop(g_test_h->demux_h);
-       mediademuxer_unprepare(g_test_h->demux_h);
-       mediademuxer_destroy(g_test_h->demux_h);
+       mediademuxer_stop(g_test_h->audio_demux_h);
+       mediademuxer_stop(g_test_h->video_demux_h);
+       if (g_test_h->audio_track_id >= 0)
+               mediademuxer_unselect_track(g_test_h->audio_demux_h, g_test_h->audio_track_id);
+       if (g_test_h->video_track_id >= 0)
+               mediademuxer_unselect_track(g_test_h->video_demux_h, g_test_h->video_track_id);
+
+       for (i = 0; i < STREAM_MAX; i++) {
+               if (!g_test_h->streams[i].thread)
+                       continue;
+
+               g_test_h->streams[i].eos_track = false;
+               g_test_h->streams[i].is_seek_queue_flushing = false;
+               STREAM_SIGNAL(i);
+
+               STREAM_LOCK(i);
+               STREAM_UNLOCK(i);
+
+               g_mutex_clear(&g_test_h->streams[i].mutex);
+               g_cond_clear(&g_test_h->streams[i].cond);
+       }
+
+       mediademuxer_unprepare(g_test_h->audio_demux_h);
+       mediademuxer_destroy(g_test_h->audio_demux_h);
+
+       mediademuxer_unprepare(g_test_h->video_demux_h);
+       mediademuxer_destroy(g_test_h->video_demux_h);
 
        esplusplayer_close(g_test_h->espp_h);
        esplusplayer_destroy(g_test_h->espp_h);
@@ -493,19 +564,6 @@ static void __deinit_test()
                }
        }
 
-       g_test_h->stop_thread = true;
-
-       for (i = 0; i < STREAM_MAX; i++) {
-               if (!g_test_h->streams[i].thread)
-                       continue;
-               g_test_h->streams[i].wait_thread = false;
-               g_test_h->streams[i].eos_track = false;
-               STREAM_SIGNAL(i);
-               pthread_join(g_test_h->streams[i].thread, NULL);
-               g_mutex_clear(&g_test_h->streams[i].mutex);
-               g_cond_clear(&g_test_h->streams[i].cond);
-       }
-
        g_free(g_test_h);
        g_free(g_uri);
 }
@@ -529,9 +587,12 @@ static void __test_demuxer_get_track_info()
                return;
        }
 
-       mediademuxer_h demuxer = g_test_h->demux_h;
+       mediademuxer_h audio_demuxer = g_test_h->audio_demux_h;
+       mediademuxer_h video_demuxer = g_test_h->video_demux_h;
+
+       mediademuxer_get_track_count(audio_demuxer, &num_tracks);
+       mediademuxer_get_track_count(video_demuxer, &num_tracks);
 
-       mediademuxer_get_track_count(demuxer, &num_tracks);
        g_print("Number of total tracks [%d]\n", num_tracks);
        if (num_tracks > MAX_TRACK_COUNT) {
                g_print("total tracks %d > %d\n", num_tracks, MAX_TRACK_COUNT);
@@ -542,7 +603,7 @@ static void __test_demuxer_get_track_info()
 
        for (; track < num_tracks; track++) {
                media_format_h get_format;
-               ret = mediademuxer_get_track_info(demuxer, track, &get_format);
+               ret = mediademuxer_get_track_info(audio_demuxer, track, &get_format);
                if (ret == 0) {
                        if (media_format_get_video_info(get_format, &mime,
                                        &w, &h, NULL, NULL) == MEDIA_FORMAT_ERROR_NONE) {
@@ -576,6 +637,13 @@ static void __test_demuxer_get_track_info()
                } else {
                        g_print("Error while getting mediademuxer_get_track_info\n");
                }
+
+               ret = mediademuxer_get_track_info(video_demuxer, track, &get_format);
+               if (ret == 0) {
+                       media_format_unref(get_format);
+                       get_format = NULL;
+               }
+
                if (track > MAX_TRACK_COUNT - 1)
                        break;
        }
@@ -588,11 +656,17 @@ static void __test_demuxer_prepare()
                return;
        }
 
-       int ret = mediademuxer_prepare(g_test_h->demux_h);
+       int ret = mediademuxer_prepare(g_test_h->audio_demux_h);
        if (ret != MEDIADEMUXER_ERROR_NONE)
-               g_print("                       => failed to mediademuxer_prepare()\n");
+               g_print("                       => failed to mediademuxer_prepare(audio)\n");
        else
-               g_print("                       => mediademuxer_prepare() success\n");
+               g_print("                       => mediademuxer_prepare(audio) success\n");
+
+       ret = mediademuxer_prepare(g_test_h->video_demux_h);
+       if (ret != MEDIADEMUXER_ERROR_NONE)
+               g_print("                       => failed to mediademuxer_prepare(video)\n");
+       else
+               g_print("                       => mediademuxer_prepare(video) success\n");
 }
 
 static void __test_set_audio_stream_info()
@@ -635,13 +709,13 @@ static void __test_set_audio_stream_info()
                return;
        }
 
-       ret = mediademuxer_read_sample(g_test_h->demux_h,
+       ret = mediademuxer_read_sample(g_test_h->audio_demux_h,
                        g_test_h->streams[AUDIO_STREAM].track_index, &audbuf);
        if (ret != MEDIADEMUXER_ERROR_NONE) {
                g_print("Error (%d) return of (Audio) mediademuxer_read_sample()\n", ret);
        } else {
                g_test_h->streams[AUDIO_STREAM].pending_packet = audbuf;
-               if (media_packet_get_codec_data (audbuf, &codec_data, &codec_data_length) == MEDIA_PACKET_ERROR_NONE) {
+               if (media_packet_get_codec_data(audbuf, &codec_data, &codec_data_length) == MEDIA_PACKET_ERROR_NONE) {
                        g_print("Audio has codec data\n");
                        audio_info.codec_data = (char *)codec_data;
                        audio_info.codec_data_length = codec_data_length;
@@ -712,13 +786,13 @@ static void __test_set_video_stream_info()
                return;
        }
 
-       ret = mediademuxer_read_sample(g_test_h->demux_h,
+       ret = mediademuxer_read_sample(g_test_h->video_demux_h,
                        g_test_h->streams[VIDEO_STREAM].track_index, &vidbuf);
        if (ret != MEDIADEMUXER_ERROR_NONE) {
                g_print("Error (%d) return of (Video) mediademuxer_read_sample()\n", ret);
        } else {
                g_test_h->streams[VIDEO_STREAM].pending_packet = vidbuf;
-               if (media_packet_get_codec_data (vidbuf, &codec_data, &codec_data_length) == MEDIA_PACKET_ERROR_NONE) {
+               if (media_packet_get_codec_data(vidbuf, &codec_data, &codec_data_length) == MEDIA_PACKET_ERROR_NONE) {
                        g_print("Video has codec data\n");
                        video_info.codec_data = (char *)codec_data;
                        video_info.codec_data_length = codec_data_length;
@@ -842,7 +916,7 @@ static void __convert_espp_packet(media_packet_h packet, esplusplayer_es_packet*
                return;
        }
 
-       media_packet_is_audio (packet, &is_audio);
+       media_packet_is_audio(packet, &is_audio);
        espp_packet->type = is_audio ? ESPLUSPLAYER_STREAM_TYPE_AUDIO : ESPLUSPLAYER_STREAM_TYPE_VIDEO;
 
        media_packet_get_buffer_data_ptr(packet, (void **)&espp_packet->buffer);
@@ -850,9 +924,9 @@ static void __convert_espp_packet(media_packet_h packet, esplusplayer_es_packet*
        media_packet_get_pts(packet, &gst_pts);
        media_packet_get_duration(packet, &gst_duration);
        if (gst_pts != (uint64_t) -1)
-               espp_packet->pts = gst_pts / G_GINT64_CONSTANT (1000000);
+               espp_packet->pts = gst_pts / G_GINT64_CONSTANT(1000000);
        if (gst_duration != (uint64_t) -1)
-               espp_packet->duration = gst_duration / G_GINT64_CONSTANT (1000000);
+               espp_packet->duration = gst_duration / G_GINT64_CONSTANT(1000000);
 
        espp_packet->matroska_color_info = NULL;
        espp_packet->hdr10p_metadata = NULL;
@@ -862,20 +936,19 @@ void *_fetch_audio_data(void *ptr)
 {
        int ret = MEDIADEMUXER_ERROR_NONE;
        int *status = (int *)g_malloc(sizeof(int));
-       esplusplayer_submit_status submit_status;
+       esplusplayer_submit_status submit_status = ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED;
        test_h *test_t = (test_h *)ptr;
 
        *status = -1;
+       g_print("Audio Data function\n");
 
        if (test_t->streams[AUDIO_STREAM].pending_packet) {
                media_packet_h pending = test_t->streams[AUDIO_STREAM].pending_packet;
                esplusplayer_es_packet pending_espp_packet;
                __convert_espp_packet(pending, &pending_espp_packet);
                submit_status = esplusplayer_submit_packet(test_t->espp_h, &pending_espp_packet);
-#ifdef DEBUG_LOG
                g_print("Audio pending packet[media:%p, es:%p][%" PRIu64 " ms] espp submit packet status[%d]\n",
                                pending, &pending_espp_packet, pending_espp_packet.pts ,submit_status);
-#endif
                media_packet_destroy(pending);
                test_t->streams[AUDIO_STREAM].pending_packet = NULL;
        }
@@ -884,47 +957,66 @@ void *_fetch_audio_data(void *ptr)
                esplusplayer_es_packet espp_packet;
                media_packet_h audbuf;
 
-               if (test_t->streams[AUDIO_STREAM].wait_thread) {
-                       STREAM_LOCK(AUDIO_STREAM);
+               STREAM_LOCK(AUDIO_STREAM);
+               if (test_t->streams[AUDIO_STREAM].wait_thread
+                               || test_t->streams[AUDIO_STREAM].is_seek_queue_flushing) {
                        STREAM_WAIT(AUDIO_STREAM);
-                       test_t->streams[AUDIO_STREAM].wait_thread = false;
-                       STREAM_UNLOCK(AUDIO_STREAM);
                }
 
-               if (test_t->stop_thread)
+               if (test_t->stop_thread) {
+                       STREAM_UNLOCK(AUDIO_STREAM);
                        pthread_exit(NULL);
+               }
 
-               ret = mediademuxer_read_sample(test_t->demux_h,
+               ret = mediademuxer_read_sample(test_t->audio_demux_h,
                                test_t->streams[AUDIO_STREAM].track_index, &audbuf);
                if (ret != MEDIADEMUXER_ERROR_NONE) {
                        g_print("Error (%x) return of (Audio) mediademuxer_read_sample()\n", ret);
+                       STREAM_UNLOCK(AUDIO_STREAM);
                        pthread_exit(NULL);
                }
                if (test_t->streams[AUDIO_STREAM].eos_track) {
                        submit_status = esplusplayer_submit_eos_packet(test_t->espp_h, ESPLUSPLAYER_STREAM_TYPE_AUDIO);
                        g_print("espp submit audio EOS packet status[%d]\n", submit_status);
-                       STREAM_LOCK(AUDIO_STREAM);
                        test_t->streams[AUDIO_STREAM].wait_thread = true;
                        g_print("Audio EOS wait thread\n");
                        STREAM_WAIT(AUDIO_STREAM);
-                       test_t->streams[AUDIO_STREAM].wait_thread = false;
                        STREAM_UNLOCK(AUDIO_STREAM);
                        continue;
                }
 
-               if (test_t->stop_thread)
+               if (test_t->stop_thread) {
+                       STREAM_UNLOCK(AUDIO_STREAM);
                        pthread_exit(NULL);
+               }
 
                __convert_espp_packet(audbuf, &espp_packet);
-               submit_status = esplusplayer_submit_packet(test_t->espp_h, &espp_packet);
+               while (!test_t->stop_thread
+                                       && (submit_status = esplusplayer_submit_packet(test_t->espp_h, &espp_packet)) == ESPLUSPLAYER_SUBMIT_STATUS_FULL) {
+                       if (test_t->streams[AUDIO_STREAM].is_seek_queue_flushing)
+                               break;
+
+                       test_t->streams[AUDIO_STREAM].is_full_waiting = true;
+                       if (test_t->is_seek_done) {
+                               STREAM_WAIT(AUDIO_STREAM);
+                       } else {
+                               STREAM_WAIT_UNTIL(AUDIO_STREAM, SEEK_WAIT_TIME);
+                       }
+                       test_t->streams[AUDIO_STREAM].is_full_waiting = false;
+               }
 #ifdef DEBUG_LOG
-               g_print("Audio packet[media:%p, es:%p][%" PRIu64 " ms] espp submit packet status[%d]\n",
-                               audbuf, &espp_packet, espp_packet.pts ,submit_status);
+               if (!test_t->streams[AUDIO_STREAM].is_seek_queue_flushing) {
+                       g_print("Audio packet[media:%p, es:%p][%" PRIu64 " ms] espp submit packet status[%d]\n",
+                                       audbuf, &espp_packet, espp_packet.pts ,submit_status);
+               }
 #endif
                media_packet_destroy(audbuf);
+               STREAM_UNLOCK(AUDIO_STREAM);
        }
 
-       g_print("EOS return of mediademuxer_read_sample() for audio\n");
+       if (!test_t->stop_thread)
+               g_print("EOS return of mediademuxer_read_sample() for audio\n");
+
        *status = 0;
        return (void *)status;
 }
@@ -933,7 +1025,7 @@ void *_fetch_video_data(void *ptr)
 {
        int ret = MEDIADEMUXER_ERROR_NONE;
        int *status = (int *)g_malloc(sizeof(int));
-       esplusplayer_submit_status submit_status;
+       esplusplayer_submit_status submit_status = ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED;
        test_h *test_t = (test_h *)ptr;
 
        *status = -1;
@@ -954,47 +1046,67 @@ void *_fetch_video_data(void *ptr)
                esplusplayer_es_packet espp_packet;
                media_packet_h vidbuf;
 
-               if (test_t->streams[VIDEO_STREAM].wait_thread) {
-                       STREAM_LOCK(VIDEO_STREAM);
+               STREAM_LOCK(VIDEO_STREAM);
+               if (test_t->streams[VIDEO_STREAM].wait_thread
+                               || test_t->streams[VIDEO_STREAM].is_seek_queue_flushing) {
                        STREAM_WAIT(VIDEO_STREAM);
-                       test_t->streams[VIDEO_STREAM].wait_thread = false;
-                       STREAM_UNLOCK(VIDEO_STREAM);
                }
 
-               if (test_t->stop_thread)
+               if (test_t->stop_thread) {
+                       STREAM_UNLOCK(VIDEO_STREAM);
                        pthread_exit(NULL);
+               }
 
-               ret = mediademuxer_read_sample(test_t->demux_h,
+               ret = mediademuxer_read_sample(test_t->video_demux_h,
                                test_t->streams[VIDEO_STREAM].track_index, &vidbuf);
                if (ret != MEDIADEMUXER_ERROR_NONE) {
                        g_print("Error (%d) return of (Video) mediademuxer_read_sample()\n", ret);
+                       STREAM_UNLOCK(VIDEO_STREAM);
                        pthread_exit(NULL);
                }
                if (test_t->streams[VIDEO_STREAM].eos_track) {
                        submit_status = esplusplayer_submit_eos_packet(test_t->espp_h, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
                        g_print("espp submit video EOS packet status[%d]\n", submit_status);
-                       STREAM_LOCK(VIDEO_STREAM);
                        test_t->streams[VIDEO_STREAM].wait_thread = true;
                        g_print("Video EOS wait thread\n");
                        STREAM_WAIT(VIDEO_STREAM);
-                       test_t->streams[VIDEO_STREAM].wait_thread = false;
                        STREAM_UNLOCK(VIDEO_STREAM);
                        continue;
                }
 
-               if (test_t->stop_thread)
+               if (test_t->stop_thread) {
+                       STREAM_UNLOCK(VIDEO_STREAM);
                        pthread_exit(NULL);
+               }
 
                __convert_espp_packet(vidbuf, &espp_packet);
-               submit_status = esplusplayer_submit_packet(test_t->espp_h, &espp_packet);
+               while (!test_t->stop_thread
+                                       && (submit_status = esplusplayer_submit_packet(test_t->espp_h, &espp_packet)) == ESPLUSPLAYER_SUBMIT_STATUS_FULL) {
+                       if (test_t->streams[VIDEO_STREAM].is_seek_queue_flushing)
+                               break;
+
+                       test_t->streams[VIDEO_STREAM].is_full_waiting = true;
+                       if (test_t->is_seek_done) {
+                               STREAM_WAIT(VIDEO_STREAM);
+                       } else {
+                               STREAM_WAIT_UNTIL(VIDEO_STREAM, SEEK_WAIT_TIME);
+                       }
+                       test_t->streams[VIDEO_STREAM].is_full_waiting = false;
+               }
 #ifdef DEBUG_LOG
-               g_print("Video packet[media:%p, es:%p][%" PRIu64 " ms] espp submit packet status[%d]\n", vidbuf, &espp_packet, espp_packet.pts ,submit_status);
+               if (!test_t->streams[VIDEO_STREAM].is_seek_queue_flushing) {
+                       g_print("Video packet[media:%p, es:%p][%" PRIu64 " ms] espp submit packet status[%d]\n",
+                                       vidbuf, &espp_packet, espp_packet.pts ,submit_status);
+               }
 #endif
                media_packet_destroy(vidbuf);
+               STREAM_UNLOCK(VIDEO_STREAM);
        }
-       g_print("EOS return of mediademuxer_read_sample() for video\n");
-       *status = 0;
 
+       if (!test_t->stop_thread)
+               g_print("EOS return of mediademuxer_read_sample() for video\n");
+
+       *status = 0;
        return (void *)status;
 }
 
@@ -1082,22 +1194,43 @@ static void __test_pause()
 
 static void __test_seek(uint64_t time_ms)
 {
+       int i = 0;
        int ret = 0;
        if (!g_test_h) {
                g_print("test handle is NULL\n");
                return;
        }
 
-       g_test_h->streams[AUDIO_STREAM].eos_track = false;
-       g_test_h->streams[AUDIO_STREAM].wait_thread = true;
-       g_test_h->streams[VIDEO_STREAM].eos_track = false;
-       g_test_h->streams[VIDEO_STREAM].wait_thread = true;
+       if (!g_test_h->is_seek_done) {
+               g_print("Processing previous seek request\n");
+               return;
+       }
+
+       g_test_h->is_seek_done = false;
+       for (i = 0; i < STREAM_MAX; i++) {
+               if (!g_test_h->streams[i].thread)
+                       continue;
+
+               g_test_h->streams[i].is_seek_queue_flushing = true;
+               STREAM_LOCK(i);
+               if (g_test_h->streams[i].is_full_waiting)
+                       STREAM_SIGNAL(i);
+               g_test_h->streams[i].wait_thread = true;
+               g_test_h->streams[i].eos_track = false;
+               STREAM_UNLOCK(i);
+       }
 
-       ret = mediademuxer_seek(g_test_h->demux_h, time_ms);
+       ret = mediademuxer_seek(g_test_h->audio_demux_h, time_ms);
        if (ret != MEDIADEMUXER_ERROR_NONE)
-               g_print("                       => failed to mediademuxer_seek(%" PRIu64 ")\n", time_ms);
+               g_print("                       => failed to mediademuxer_seek(audio, %" PRIu64 ")\n", time_ms);
        else
-               g_print("                       => mediademuxer_seek(%" PRIu64 ") success\n", time_ms);
+               g_print("                       => mediademuxer_seek(audio, %" PRIu64 ") success\n", time_ms);
+
+       ret = mediademuxer_seek(g_test_h->video_demux_h, time_ms);
+       if (ret != MEDIADEMUXER_ERROR_NONE)
+               g_print("                       => failed to mediademuxer_seek(video, %" PRIu64 ")\n", time_ms);
+       else
+               g_print("                       => mediademuxer_seek(video, %" PRIu64 ") success\n", time_ms);
 
        ret = esplusplayer_seek(g_test_h->espp_h, time_ms);
        if (ret != ESPLUSPLAYER_ERROR_TYPE_NONE)
@@ -1425,13 +1558,23 @@ static void __test_quick_prepare()
                return;
        }
 
-       if (mediademuxer_set_data_source(g_test_h->demux_h, g_uri) != MEDIADEMUXER_ERROR_NONE) {
-               g_print("                       => failed to mediademuxer_set_data_source()\n");
+       if (mediademuxer_set_data_source(g_test_h->audio_demux_h, g_uri) != MEDIADEMUXER_ERROR_NONE) {
+               g_print("                       => failed to mediademuxer_set_data_source(audio)\n");
+               return;
+       }
+
+       if (mediademuxer_set_data_source(g_test_h->video_demux_h, g_uri) != MEDIADEMUXER_ERROR_NONE) {
+               g_print("                       => failed to mediademuxer_set_data_source(video)\n");
+               return;
+       }
+
+       if (mediademuxer_prepare(g_test_h->audio_demux_h) != MEDIADEMUXER_ERROR_NONE) {
+               g_print("                       => failed to mediademuxer_prepare(audio)\n");
                return;
        }
 
-       if (mediademuxer_prepare(g_test_h->demux_h) != MEDIADEMUXER_ERROR_NONE) {
-               g_print("                       => failed to mediademuxer_prepare()\n");
+       if (mediademuxer_prepare(g_test_h->video_demux_h) != MEDIADEMUXER_ERROR_NONE) {
+               g_print("                       => failed to mediademuxer_prepare(video)\n");
                return;
        }
 
@@ -1440,7 +1583,7 @@ static void __test_quick_prepare()
        if (g_test_h->video_track_id >= 0) {
                g_test_h->streams[VIDEO_STREAM].format = g_test_h->track_format[g_test_h->video_track_id];
                g_test_h->streams[VIDEO_STREAM].track_index = g_test_h->video_track_id;
-               if (mediademuxer_select_track(g_test_h->demux_h, g_test_h->video_track_id) != MEDIADEMUXER_ERROR_NONE) {
+               if (mediademuxer_select_track(g_test_h->video_demux_h, g_test_h->video_track_id) != MEDIADEMUXER_ERROR_NONE) {
                        g_print("                       => failed to mediademuxer_select_track() for video\n");
                        return;
                }
@@ -1449,14 +1592,19 @@ static void __test_quick_prepare()
        if (g_test_h->audio_track_id >= 0) {
                g_test_h->streams[AUDIO_STREAM].format = g_test_h->track_format[g_test_h->audio_track_id];
                g_test_h->streams[AUDIO_STREAM].track_index = g_test_h->audio_track_id;
-               if (mediademuxer_select_track(g_test_h->demux_h, g_test_h->audio_track_id) != MEDIADEMUXER_ERROR_NONE) {
+               if (mediademuxer_select_track(g_test_h->audio_demux_h, g_test_h->audio_track_id) != MEDIADEMUXER_ERROR_NONE) {
                        g_print("                       => failed to mediademuxer_select_track() for audio\n");
                        return;
                }
        }
 
-       if (mediademuxer_start(g_test_h->demux_h) != MEDIADEMUXER_ERROR_NONE) {
-               g_print("                       => failed to mediademuxer_start()\n");
+       if (mediademuxer_start(g_test_h->audio_demux_h) != MEDIADEMUXER_ERROR_NONE) {
+               g_print("                       => failed to mediademuxer_start(audio)\n");
+               return;
+       }
+
+       if (mediademuxer_start(g_test_h->video_demux_h) != MEDIADEMUXER_ERROR_NONE) {
+               g_print("                       => failed to mediademuxer_start(video)\n");
                return;
        }
 
@@ -1483,9 +1631,13 @@ static void __input_filename(char *filename)
                return;
        }
 
-       ret = mediademuxer_set_data_source(g_test_h->demux_h, filename);
+       ret = mediademuxer_set_data_source(g_test_h->audio_demux_h, filename);
+       if (ret != MEDIADEMUXER_ERROR_NONE)
+               g_print("                       => failed to mediademuxer_set_data_source(audio)\n");
+
+       ret = mediademuxer_set_data_source(g_test_h->video_demux_h, filename);
        if (ret != MEDIADEMUXER_ERROR_NONE)
-               g_print("                       => failed to mediademuxer_set_data_source()\n");
+               g_print("                       => failed to mediademuxer_set_data_source(video)\n");
 }
 
 static void __interpret_main_menu(char *cmd)
@@ -1518,6 +1670,10 @@ static void __interpret_main_menu(char *cmd)
                        g_menu_state = CURRENT_STATUS_SET_MUTE;
                } else if (strncmp(cmd, "q", 1) == 0) {
                        quit_program();
+               } else if (strncmp(cmd, "3", 1) == 0) {
+                       if (g_max_range > 0)
+                               __test_seek(g_rand_int_range(g_seek_rand, 0, g_max_range));
+                       g_menu_state = CURRENT_STATUS_MAINMENU;
                } else {
                        g_print("unknown menu \n");
                }
@@ -1570,6 +1726,8 @@ static void __interpret_main_menu(char *cmd)
                        g_menu_state = CURRENT_STATUS_SET_DISPLAY_ROTATION;
                } else if (strncmp(cmd, "ssi", 3) == 0) {
                        g_menu_state = CURRENT_STATUS_SET_SOUND_STREAM_INFO;
+               } else if (strncmp(cmd, "ssr", 3) == 0) {
+                       g_menu_state = CURRENT_STATUS_SET_SEEK_RANGE;
                } else {
                        g_print("unknown menu \n");
                }
@@ -1604,7 +1762,9 @@ static void __display_sub_basic()
        g_print("e.Pause\t\t");
        g_print("dt.Destroy\n");
        g_print("[quick] qp.quick prepare\n");
-       g_print("[seek] j.Seek\t\t");
+       g_print("[seek] j.Seek\t");
+       g_print("3.Random seek\t");
+       g_print("ssr. Set random seek range\n");
        g_print("[trick] tr.set playback rate\n");
        g_print("[State] S.Get state\n");
        g_print("[volume] f.Set Volume\t");
@@ -1641,6 +1801,8 @@ static void __displaymenu()
                g_print("*** Input deactivate stream.(0:audio, 1:video)\n");
        } else if (g_menu_state == CURRENT_STATUS_SEEK) {
                g_print("*** Input seek position.(ms)\n");
+       } else if (g_menu_state == CURRENT_STATUS_SET_SEEK_RANGE) {
+               g_print("*** Input random seek range.(ms)\n");
        } else if (g_menu_state == CURRENT_STATUS_SET_RATE) {
                g_print("*** Input playback rate.(rate(0.0~2.0), audio_mute)\n");
        } else if (g_menu_state == CURRENT_STATUS_SET_VOLUME) {
@@ -1733,6 +1895,13 @@ static void interpret(char *cmd)
                reset_menu_state();
                break;
        }
+       case CURRENT_STATUS_SET_SEEK_RANGE:
+       {
+               value = (int)atoi(cmd);
+               g_max_range = value;
+               reset_menu_state();
+               break;
+       }
        case CURRENT_STATUS_SET_RATE:
        {
                static float rate;
@@ -1877,7 +2046,7 @@ static void interpret(char *cmd)
                        if (value != -1) {
                                g_test_h->streams[VIDEO_STREAM].format = g_test_h->track_format[value];
                                g_test_h->streams[VIDEO_STREAM].track_index = value;
-                               ret = mediademuxer_select_track(g_test_h->demux_h, g_test_h->streams[VIDEO_STREAM].track_index);
+                               ret = mediademuxer_select_track(g_test_h->video_demux_h, g_test_h->streams[VIDEO_STREAM].track_index);
                                if (ret != MEDIADEMUXER_ERROR_NONE)
                                        g_print("                       => failed to mediademuxer_select_track(video)\n");
                                else
@@ -1892,17 +2061,24 @@ static void interpret(char *cmd)
                        if (value != -1) {
                                g_test_h->streams[AUDIO_STREAM].format = g_test_h->track_format[value];
                                g_test_h->streams[AUDIO_STREAM].track_index = value;
-                               ret = mediademuxer_select_track(g_test_h->demux_h, g_test_h->streams[AUDIO_STREAM].track_index);
+                               ret = mediademuxer_select_track(g_test_h->audio_demux_h, g_test_h->streams[AUDIO_STREAM].track_index);
                                if (ret != MEDIADEMUXER_ERROR_NONE)
                                        g_print("                       => failed to mediademuxer_select_track(audio)\n");
                                else
                                        g_print("                       => mediademuxer_select_track(audio) success\n");
                        }
-                       ret = mediademuxer_start(g_test_h->demux_h);
+
+                       ret = mediademuxer_start(g_test_h->audio_demux_h);
+                       if (ret != MEDIADEMUXER_ERROR_NONE)
+                               g_print("                       => failed to mediademuxer_start(audio)\n");
+                       else
+                               g_print("                       => mediademuxer_start(audio) success\n");
+
+                       ret = mediademuxer_start(g_test_h->video_demux_h);
                        if (ret != MEDIADEMUXER_ERROR_NONE)
-                               g_print("                       => failed to mediademuxer_start()\n");
+                               g_print("                       => failed to mediademuxer_start(video)\n");
                        else
-                               g_print("                       => mediademuxer_start() success\n");
+                               g_print("                       => mediademuxer_start(video) success\n");
 
                        reset_menu_state();
                        break;