diff options
author | Hyunil Park <hyunil46.park@samsung.com> | 2015-07-27 14:10:50 +0900 |
---|---|---|
committer | Hyunil Park <hyunil46.park@samsung.com> | 2015-07-27 14:10:50 +0900 |
commit | 3a07a7dc34f0011c93a113a7c959353913652d12 (patch) | |
tree | d8dfbbf9db2d48c59764f01bff70afd910e8762c | |
parent | 878ef7e8158538789cfabc3666b93f7577911f06 (diff) | |
download | libmm-player-3a07a7dc34f0011c93a113a7c959353913652d12.tar.gz libmm-player-3a07a7dc34f0011c93a113a7c959353913652d12.tar.bz2 libmm-player-3a07a7dc34f0011c93a113a7c959353913652d12.zip |
add segment handling to support gapless playback on gstreamer 1.x
Change-Id: I86e5de53711401c0395b201f1eb22e33f48c776c
Signed-off-by: Hyunil Park <hyunil46.park@samsung.com>
-rw-r--r-- | packaging/libmm-player.spec | 2 | ||||
-rw-r--r-- | src/include/mm_player_priv.h | 18 | ||||
-rw-r--r-- | src/mm_player_priv.c | 144 |
3 files changed, 130 insertions, 34 deletions
diff --git a/packaging/libmm-player.spec b/packaging/libmm-player.spec index 142b1d8..86e7af6 100644 --- a/packaging/libmm-player.spec +++ b/packaging/libmm-player.spec @@ -3,7 +3,7 @@ Name: libmm-player Summary: Multimedia Framework Player Library -Version: 0.5.62 +Version: 0.5.63 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 ff154b8..e3d2c2a 100644 --- a/src/include/mm_player_priv.h +++ b/src/include/mm_player_priv.h @@ -404,6 +404,7 @@ typedef struct { gint active_pad_index; gint total_track_num; GPtrArray *channels; + gulong event_probe_id; } mm_player_selector_t; /* Things needed to be done after output device has changed */ @@ -417,6 +418,18 @@ typedef struct { } mm_player_post_proc_t; typedef struct { + gboolean running; + + gboolean stream_changed; + gboolean reconfigure; + + GstClockTime next_pts; /* latest decoded buffer's pts+duration */ + GstClockTime start_time; /* updated once get SEGMENT event */ + + gulong audio_data_probe_id; +} mm_player_gapless_t; + +typedef struct { /* STATE */ int state; // player current state int prev_state; // player previous state @@ -448,6 +461,7 @@ typedef struct { gboolean next_play_thread_exit; GCond next_play_thread_cond; GMutex next_play_thread_mutex; + mm_player_gapless_t gapless; /* capture thread */ GThread* capture_thread; @@ -691,10 +705,6 @@ typedef struct { gboolean video_hub_download_mode; gboolean sync_handler; - /* seamless next playing */ - gboolean src_changed; - gboolean pp_rebuilding; - /* store dump pad list */ GList* dump_list; diff --git a/src/mm_player_priv.c b/src/mm_player_priv.c index a002800..50bd817 100644 --- a/src/mm_player_priv.c +++ b/src/mm_player_priv.c @@ -1438,16 +1438,16 @@ static gpointer __mmplayer_next_play_thread(gpointer data) debug_log("next play thread started. waiting for signal.\n"); g_cond_wait(&player->next_play_thread_cond, &player->next_play_thread_mutex ); - debug_log("re building pipeline for next play.\n"); + debug_log("reconfigure pipeline for gapless play.\n"); if ( player->next_play_thread_exit ) { - if(player->pp_rebuilding) + if(player->gapless.reconfigure) { - player->pp_rebuilding = false; + player->gapless.reconfigure = false; MMPLAYER_PLAYBACK_UNLOCK(player); } - debug_log("exiting next play thread\n"); + debug_log("exiting gapless play thread\n"); break; } @@ -2160,10 +2160,9 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @ } } - if (player->src_changed) + if (player->gapless.stream_changed) { _mmplayer_update_content_attrs(player, ATTR_ALL); - player->src_changed = FALSE; } if (player->doing_seek && async_done) @@ -2776,7 +2775,7 @@ __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) if ( ! str ) { - debug_error ("cannot get structure from capse.\n"); + debug_error ("cannot get structure from caps.\n"); goto ERROR; } @@ -3038,6 +3037,64 @@ __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer dat return GST_PAD_PROBE_OK; } +static GstPadProbeReturn +__mmplayer_audio_data_probe (GstPad *pad, GstPadProbeInfo *info, gpointer u_data) +{ + mm_player_t* player = (mm_player_t*) u_data; + GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info); + + /* TO_CHECK: performance */ + return_val_if_fail (player && GST_IS_BUFFER(pad_buffer), GST_PAD_PROBE_OK); + + if (GST_BUFFER_PTS_IS_VALID(pad_buffer) && GST_BUFFER_DURATION_IS_VALID(pad_buffer)) + player->gapless.next_pts = GST_BUFFER_PTS(pad_buffer) + GST_BUFFER_DURATION(pad_buffer); + + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +__mmplayer_gst_selector_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data) +{ + GstPadProbeReturn ret = GST_PAD_PROBE_OK; + GstEvent *event = GST_PAD_PROBE_INFO_DATA (info); + mm_player_t* player = (mm_player_t*)data; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_STREAM_START: + break; + case GST_EVENT_SEGMENT: { + GstSegment segment; + GstEvent *tmpev; + + if (!player->gapless.running) + break; + + if (player->gapless.stream_changed) { + player->gapless.start_time += player->gapless.next_pts; + player->gapless.stream_changed = FALSE; + } + + debug_log ("event: %" GST_PTR_FORMAT, event); + gst_event_copy_segment (event, &segment); + + if (segment.format == GST_FORMAT_TIME) + { + segment.base = player->gapless.start_time; + debug_log ("base of segment: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment.base)); + + tmpev = gst_event_new_segment (&segment); + gst_event_set_seqnum (tmpev, gst_event_get_seqnum (event)); + gst_event_unref (event); + GST_PAD_PROBE_INFO_DATA(info) = tmpev; + } + break; + } + default: + break; + } + return ret; +} + static void __mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data) { @@ -3076,7 +3133,7 @@ __mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data) str = gst_caps_get_structure (caps, 0); if ( ! str ) { - debug_error ("cannot get structure from capse.\n"); + debug_error ("cannot get structure from caps.\n"); goto ERROR; } @@ -3224,9 +3281,6 @@ __mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data) } g_object_set (selector, "sync-streams", TRUE, NULL); - gst_bin_add (GST_BIN(pipeline), selector); - gst_element_set_state (selector, GST_STATE_PAUSED); - player->pipeline->mainbin[elemId].id = elemId; player->pipeline->mainbin[elemId].gst = selector; @@ -3240,6 +3294,11 @@ __mmplayer_gst_decode_pad_added (GstElement *elem, GstPad *pad, gpointer data) // gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, // __mmplayer_gst_selector_blocked, NULL, NULL); + player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + __mmplayer_gst_selector_event_probe, player, NULL); + + gst_element_set_state (selector, GST_STATE_PAUSED); + gst_bin_add (GST_BIN(pipeline), selector); } else { @@ -3805,9 +3864,9 @@ __mmplayer_gst_decode_no_more_pads (GstElement *elem, gpointer data) { debug_warning("no need to go more"); - if (player->pp_rebuilding) + if (player->gapless.reconfigure) { - player->pp_rebuilding = FALSE; + player->gapless.reconfigure = FALSE; MMPLAYER_PLAYBACK_UNLOCK(player); } @@ -3941,9 +4000,9 @@ ERROR: srcpad = NULL; } - if (player->pp_rebuilding) + if (player->gapless.reconfigure) { - player->pp_rebuilding = FALSE; + player->gapless.reconfigure = FALSE; MMPLAYER_PLAYBACK_UNLOCK(player); } } @@ -3990,7 +4049,7 @@ __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // str = gst_caps_get_structure( caps, 0 ); if ( ! str ) { - debug_error("cannot get structure from capse.\n"); + debug_error("cannot get structure from caps.\n"); goto ERROR; } @@ -5585,6 +5644,9 @@ __mmplayer_gst_create_audio_pipeline(mm_player_t* player) goto ERROR; } + player->gapless.audio_data_probe_id = gst_pad_add_probe(ghostpad, GST_PAD_PROBE_TYPE_BUFFER, + __mmplayer_audio_data_probe, player, NULL); + gst_object_unref(pad); g_list_free(element_bucket); @@ -6829,7 +6891,7 @@ __mmplayer_check_useful_message(mm_player_t *player, GstMessage * message) case GST_MESSAGE_ASYNC_DONE: case GST_MESSAGE_STATE_CHANGED: /* we only handle messages from pipeline */ - if(( message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) && (!player->pp_rebuilding)) + if(( message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst ) && (!player->gapless.reconfigure)) retval = TRUE; else retval = FALSE; @@ -7850,6 +7912,28 @@ void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source MMPLAYER_FLEAVE(); } +static void +__mmplayer_reset_gapless_state(mm_player_t* player) +{ + MMPLAYER_FENTER(); + return_if_fail(player + && player->pipeline + && player->pipeline->audiobin + && player->pipeline->audiobin[MMPLAYER_A_BIN].gst); + + if (player->gapless.audio_data_probe_id != 0) + { + GstPad *sinkpad; + sinkpad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_BIN].gst, "sink"); + gst_pad_remove_probe (sinkpad, player->gapless.audio_data_probe_id); + gst_object_unref (sinkpad); + } + memset(&player->gapless, 0, sizeof(mm_player_gapless_t)); + + MMPLAYER_FLEAVE(); + return; +} + static int __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @ { @@ -7868,12 +7952,11 @@ __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @ player->demux_pad_index = 0; player->subtitle_language_list = NULL; player->use_deinterleave = FALSE; - player->pp_rebuilding = FALSE; player->max_audio_channels = 0; player->video_share_api_delta = 0; player->video_share_clock_delta = 0; player->video_hub_download_mode = 0; - + __mmplayer_reset_gapless_state(player); __mmplayer_post_proc_reset(player); if (player->streamer) @@ -9558,7 +9641,6 @@ _mmplayer_create_player(MMHandleType handle) // @ player->use_decodebin = TRUE; player->ignore_asyncdone = FALSE; player->use_deinterleave = FALSE; - player->pp_rebuilding = FALSE; player->max_audio_channels = 0; player->video_share_api_delta = 0; player->video_share_clock_delta = 0; @@ -10630,7 +10712,7 @@ static void __mmplayer_check_pipeline(mm_player_t* player) gint timeout = 0; int ret = MM_ERROR_NONE; - if (player->pp_rebuilding) + if (player->gapless.reconfigure) { debug_warning("pipeline is under construction.\n"); @@ -10665,6 +10747,7 @@ _mmplayer_stop(MMHandleType hplayer) // @ /* check pipline building state */ __mmplayer_check_pipeline(player); + player->gapless.start_time = 0; /* NOTE : application should not wait for EOS after calling STOP */ __mmplayer_cancel_eos_timer( player ); @@ -12107,11 +12190,11 @@ __mmplayer_verify_next_play_path(mm_player_t *player) MMPLAYER_FENTER(); - debug_log("checking for next play"); + debug_log("checking for gapless play"); if (player->pipeline->textbin) { - debug_error("subtitle path is enabled. next play is not supported.\n"); + debug_error("subtitle path is enabled. gapless play is not supported.\n"); goto ERROR; } @@ -12549,7 +12632,8 @@ __mmplayer_activate_next_source(mm_player_t *player, GstState target) } } - player->src_changed = TRUE; + player->gapless.stream_changed = TRUE; + player->gapless.running = TRUE; MMPLAYER_FLEAVE(); return; @@ -12603,6 +12687,10 @@ __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type) srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src"); + if (selector->event_probe_id != 0) + gst_pad_remove_probe (srcpad, selector->event_probe_id); + selector->event_probe_id = 0; + if ((sinkbin) && (sinkbin[sinkId].gst)) { sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink"); @@ -12646,7 +12734,6 @@ __mmplayer_deactivate_old_path(mm_player_t *player) MMPLAYER_FENTER(); return_if_fail ( player ); - g_object_set(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_DEC1].gst), "remove-buffer-signal", TRUE, NULL); if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) || (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) { @@ -13117,11 +13204,13 @@ __mmplayer_gst_decode_drained(GstElement *bin, gpointer data) if (!__mmplayer_verify_next_play_path(player)) { debug_log("decoding is finished."); + player->gapless.running = FALSE; + player->gapless.start_time = 0; g_mutex_unlock(&player->cmd_lock); return; } - player->pp_rebuilding = TRUE; + player->gapless.reconfigure = TRUE; /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/ __mmplayer_deactivate_old_path(player); @@ -13407,7 +13496,6 @@ __mmplayer_release_misc(mm_player_t* player) player->last_multiwin_status = FALSE; player->has_closed_caption = FALSE; player->set_mode.media_packet_video_stream = FALSE; - memset(&player->set_mode, 0, sizeof(MMPlayerSetMode)); /* recover mode */ player->set_mode.rich_audio = cur_mode; @@ -13520,8 +13608,6 @@ __mmplayer_release_misc_post(mm_player_t* player) } player->uri_info.uri_idx = 0; - player->src_changed = FALSE; - MMPLAYER_FLEAVE(); } |