From 15ef8e28eac79ef271ea57b7bfec671b49719387 Mon Sep 17 00:00:00 2001 From: Hyunil Park Date: Thu, 9 Jul 2015 10:00:36 +0900 Subject: [PATCH] add buffering control of hls streaming and remove dead code Change-Id: I4d31f016f6121d2d1c44eaee0c372ccb5696abb1 Signed-off-by: Hyunil Park --- src/include/mm_player_priv.h | 11 -- src/include/mm_player_streaming.h | 10 +- src/mm_player_priv.c | 217 +++++++++++++------------------------- src/mm_player_streaming.c | 16 +-- 4 files changed, 87 insertions(+), 167 deletions(-) diff --git a/src/include/mm_player_priv.h b/src/include/mm_player_priv.h index 515c83f..1889821 100644 --- a/src/include/mm_player_priv.h +++ b/src/include/mm_player_priv.h @@ -108,17 +108,6 @@ enum alassink_sync ALSASINK_ASYNC }; - -/** - * Enumerations of Player Mode - */ -enum MMPlayerMode { - MM_PLAYER_MODE_NONE, /**< Player mode None */ - MM_PLAYER_MODE_MIDI, /**< Player mode Midi */ - MM_PLAYER_MODE_GST, /**< Player mode Gstreamer */ -}; - - /** * Enumerations of Player Uri type */ diff --git a/src/include/mm_player_streaming.h b/src/include/mm_player_streaming.h index ab2d40f..df39f1f 100755 --- a/src/include/mm_player_streaming.h +++ b/src/include/mm_player_streaming.h @@ -39,10 +39,12 @@ #define MAX_DECODEBIN_BUFFER_BYTES (32 * 1024 * 1024) /* byte */ #define MAX_DECODEBIN_BUFFER_TIME 15 /* sec */ +#define MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES (2 * 1024 * 1024) /* byte */ +#define MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME 5 /* sec */ #define DEFAULT_BUFFER_SIZE_BYTES 4194304 /* 4 MBytes */ #define DEFAULT_PLAYING_TIME 10 /* 10 sec */ -#define DEFAULT_LIVE_PLAYING_TIME 3 /* 3 sec */ +#define DEFAULT_ADAPTIVE_PLAYING_TIME 3 /* 3 sec */ #define DEFAULT_BUFFERING_TIME 3.0 /* 3sec */ #define DEFAULT_BUFFER_LOW_PERCENT 1.0 /* 1% */ @@ -81,7 +83,9 @@ do \ #define IS_DEMUXED_BUFFERING_MODE(sr) (PLAYER_STREAM_CAST(sr)->streaming_buffer_type == BUFFER_TYPE_DEMUXED)?(TRUE):(FALSE) #define GET_NEW_BUFFERING_BYTE(size) ((size) < MAX_DECODEBIN_BUFFER_BYTES)?(size):(MAX_DECODEBIN_BUFFER_BYTES) - +#define GET_MAX_BUFFER_BYTES(sr) ((PLAYER_STREAM_CAST(sr)->is_adaptive_streaming)?(MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES):(MAX_DECODEBIN_BUFFER_BYTES)) +#define GET_MAX_BUFFER_TIME(sr) ((PLAYER_STREAM_CAST(sr)->is_adaptive_streaming)?(MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME):(MAX_DECODEBIN_BUFFER_TIME)) +#define GET_DEFAULT_PLAYING_TIME(sr) ((PLAYER_STREAM_CAST(sr)->is_adaptive_streaming)?(DEFAULT_ADAPTIVE_PLAYING_TIME):(DEFAULT_PLAYING_TIME)) typedef enum { BUFFER_TYPE_DEFAULT, @@ -128,6 +132,7 @@ typedef struct gboolean is_buffering; gboolean is_buffering_done; /* get info from bus sync callback */ + gboolean is_adaptive_streaming; gint buffering_percent; @@ -156,7 +161,6 @@ void __mm_player_streaming_set_queue2( mm_player_streaming_t* streamer, void __mm_player_streaming_set_multiqueue( mm_player_streaming_t* streamer, GstElement* buffer, gboolean use_buffering, - guint buffering_bytes, gdouble buffering_time, gdouble low_percent, gdouble high_percent); diff --git a/src/mm_player_priv.c b/src/mm_player_priv.c index 9eed8e1..40cb865 100644 --- a/src/mm_player_priv.c +++ b/src/mm_player_priv.c @@ -2654,7 +2654,7 @@ __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink return_val_if_fail(player && player->pipeline, FALSE); - /* if we have no fakesink. this meas we are using decodebin2 which doesn' + /* if we have no fakesink. this meas we are using decodebin which doesn' t need to add extra fakesink */ return_val_if_fail(fakesink, TRUE); @@ -6960,7 +6960,7 @@ __mmplayer_gst_create_decoder ( mm_player_t *player, MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_decode_pad_added), player); - /* This signal is emitted whenever decodebin2 finds a new stream. It is emitted + /* This signal is emitted whenever decodebin finds a new stream. It is emitted before looking for any elements that can handle that stream.*/ MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); @@ -9140,8 +9140,8 @@ static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParse /* dump parse result */ secure_debug_warning("incomming uri : %s\n", uri); - debug_log("uri_type : %d, play_mode : %d, mem : 0x%x, mem_size : %d, urgent : %s\n", - data->uri_type, data->play_mode, (guint)data->mem, data->mem_size, data->urgent); + debug_log("uri_type : %d, mem : 0x%x, mem_size : %d, urgent : %s\n", + data->uri_type, (guint)data->mem, data->mem_size, data->urgent); MMPLAYER_FLEAVE(); @@ -11147,6 +11147,37 @@ __mmplayer_set_audio_attrs (mm_player_t* player, GstCaps* caps) } static void +__mmplayer_update_content_type_info(mm_player_t* player) +{ + MMPLAYER_FENTER(); + return_if_fail( player && player->type); + + if (__mmplayer_is_midi_type(player->type)) + { + player->bypass_audio_effect = TRUE; + } + else if (g_strrstr(player->type, "application/x-hls")) + { + /* If it can't know exact type when it parses uri because of redirection case, + * it will be fixed by typefinder or when doing autoplugging. + */ + player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS; + if (player->streamer) + { + player->streamer->is_adaptive_streaming = TRUE; + player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED; + player->streamer->buffering_req.runtime_second = 5; + } + } + else if (g_strrstr(player->type, "application/dash+xml")) + { + player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH; + } + + MMPLAYER_FLEAVE(); +} + +static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @ GstCaps *caps, gpointer data) { @@ -11183,23 +11214,7 @@ GstCaps *caps, gpointer data) return; } - /* midi type should be stored because it will be used to set audio gain in avsysaudiosink */ - if ( __mmplayer_is_midi_type(player->type)) - { - player->profile.play_mode = MM_PLAYER_MODE_MIDI; - player->bypass_audio_effect = TRUE; - } - else if ( g_strrstr(player->type, "application/x-hls")) - { - /* If it can't know exact type when it parses uri because of redirection case, - * it will be fixed by typefinder here. - */ - player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS; - } - else if ( g_strrstr(player->type, "application/dash+xml")) - { - player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH; - } + __mmplayer_update_content_type_info(player); pad = gst_element_get_static_pad(tf, "src"); if ( !pad ) @@ -11306,17 +11321,17 @@ __mmplayer_create_decodebin (mm_player_t* player) MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(__mmplayer_gst_decode_unknown_type), player ); - /* This signal is emitted whenever decodebin2 finds a new stream. It is emitted + /* This signal is emitted whenever decodebin finds a new stream. It is emitted before looking for any elements that can handle that stream.*/ MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player); - /* This signal is emitted whenever decodebin2 finds a new stream. It is emitted + /* This signal is emitted whenever decodebin finds a new stream. It is emitted before looking for any elements that can handle that stream.*/ MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player); - /* This signal is emitted once decodebin2 has finished decoding all the data.*/ + /* This signal is emitted once decodebin has finished decoding all the data.*/ MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained", G_CALLBACK(__mmplayer_gst_decode_drained), player); @@ -11332,7 +11347,7 @@ static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps) { MMPlayerGstElement* mainbin = NULL; - GstElement* decodebin2 = NULL; + GstElement* decodebin = NULL; GstElement* queue2 = NULL; GstPad* sinkpad = NULL; GstPad* qsrcpad= NULL; @@ -11436,54 +11451,64 @@ __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstC } /* create decodebin */ - decodebin2 = __mmplayer_create_decodebin(player); + decodebin = __mmplayer_create_decodebin(player); - if (!decodebin2) + if (!decodebin) { debug_error("can not create autoplug element\n"); goto ERROR; } - if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin2)) + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) { - debug_error("failed to add decodebin2\n"); + debug_error("failed to add decodebin\n"); goto ERROR; } /* to force caps on the decodebin element and avoid reparsing stuff by * typefind. It also avoids a deadlock in the way typefind activates pads in * the state change */ - g_object_set (decodebin2, "sink-caps", caps, NULL); + g_object_set (decodebin, "sink-caps", caps, NULL); - sinkpad = gst_element_get_static_pad(decodebin2, "sink"); + sinkpad = gst_element_get_static_pad(decodebin, "sink"); if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) { - debug_error("failed to link decodebin2\n"); + debug_error("failed to link decodebin\n"); goto ERROR; } gst_object_unref(GST_OBJECT(sinkpad)); mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG; - mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin2; + mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin; + /* set decodebin property about buffer in streaming playback. * + * in case of hls, it does not need to have big buffer * + * because it is kind of adaptive streaming. */ if ( ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING (player)) { + guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES; + guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME; init_buffering_time = (init_buffering_time != 0)?(init_buffering_time):(player->ini.http_buffering_time); - g_object_set (G_OBJECT(decodebin2), "use-buffering", TRUE, + if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) { + max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES; + max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME; + } + + g_object_set (G_OBJECT(decodebin), "use-buffering", TRUE, "high-percent", (gint)player->ini.http_buffering_limit, "low-percent", 1, // 1% - "max-size-bytes", MAX_DECODEBIN_BUFFER_BYTES, - "max-size-time", (guint64)(MAX_DECODEBIN_BUFFER_TIME * GST_SECOND), + "max-size-bytes", max_size_bytes, + "max-size-time", (guint64)(max_size_time * GST_SECOND), "max-size-buffers", 0, NULL); // disable or automatic } - if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin2)) + if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) { - debug_error("failed to sync decodebin2 state with parent\n"); + debug_error("failed to sync decodebin state with parent\n"); goto ERROR; } @@ -11514,21 +11539,21 @@ ERROR: queue2 = NULL; } - if (decodebin2) + if (decodebin) { /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state. * You need to explicitly set elements to the NULL state before * dropping the final reference, to allow them to clean up. */ - gst_element_set_state(decodebin2, GST_STATE_NULL); + gst_element_set_state(decodebin, GST_STATE_NULL); /* And, it still has a parent "player". * You need to let the parent manage the object instead of unreffing the object directly. */ - gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin2); - gst_object_unref (decodebin2); - decodebin2 = NULL; + gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin); + gst_object_unref (decodebin); + decodebin = NULL; } return FALSE; @@ -12506,7 +12531,7 @@ __mmplayer_activate_next_source(mm_player_t *player, GstState target) { if (gst_element_set_state (mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) { - debug_error("Failed to change state of decodebin2\n"); + debug_error("Failed to change state of decodebin\n"); goto ERROR; } } @@ -12873,24 +12898,7 @@ GstCaps* caps, GstElementFactory* factory, gpointer data) if (player->type == NULL) { player->type = gst_caps_to_string(caps); - - /* midi type should be stored because it will be used to set audio gain in avsysaudiosink */ - if (__mmplayer_is_midi_type(player->type)) - { - player->profile.play_mode = MM_PLAYER_MODE_MIDI; - player->bypass_audio_effect = TRUE; - } - else if (g_strrstr(player->type, "application/x-hls")) - { - /* If it can't know exact type when it parses uri because of redirection case, - * it will be fixed by typefinder here. - */ - player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS; - } - else if (g_strrstr(player->type, "application/dash+xml")) - { - player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH; - } + __mmplayer_update_content_type_info(player); } /* filtering exclude keyword */ @@ -13249,15 +13257,10 @@ __mmplayer_gst_element_added (GstElement *bin, GstElement *element, gpointer dat if ((MMPLAYER_IS_HTTP_STREAMING(player)) || (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) { - - if ((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) && - (player->streamer->buffering_req.initial_second == 0)) - player->streamer->buffering_req.initial_second = DEFAULT_LIVE_PLAYING_TIME; - + /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/ __mm_player_streaming_set_multiqueue(player->streamer, element, TRUE, - MAX_DECODEBIN_BUFFER_BYTES, // player->ini.http_max_size_bytes, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit); @@ -14345,84 +14348,6 @@ static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer da return; } -/* test API for tuning audio gain. this API should be - * deprecated before the day of final release - */ -int -_mmplayer_set_volume_tune(MMHandleType hplayer, MMPlayerVolumeType volume) -{ - mm_player_t* player = (mm_player_t*) hplayer; - gint error = MM_ERROR_NONE; - gint vol_max = 0; - gboolean isMidi = FALSE; - gint i = 0; - - MMPLAYER_FENTER(); - - return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED ); - return_val_if_fail( player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED ) - - debug_log("clip type=%d(1-midi, 0-others), volume [L]=%d:[R]=%d\n", - player->profile.play_mode, volume.level[0], volume.level[1]); - - isMidi = ( player->profile.play_mode == MM_PLAYER_MODE_MIDI ) ? TRUE : FALSE; - - if ( isMidi ) - vol_max = 1000; - else - vol_max = 100; - - /* is it proper volume level? */ - for (i = 0; i < MM_VOLUME_CHANNEL_NUM; ++i) - { - if (volume.level[i] < 0 || volume.level[i] > vol_max) { - debug_log("Invalid Volume level!!!! \n"); - return MM_ERROR_INVALID_ARGUMENT; - } - } - - if ( isMidi ) - { - if ( player->pipeline->mainbin ) - { - GstElement *midi_element = player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst; - - if ( midi_element && ( strstr(GST_ELEMENT_NAME(midi_element), "midiparse")) ) - { - debug_log("setting volume (%d) level to midi plugin\n", volume.level[0]); - - g_object_set(midi_element, "volume", volume.level[0], NULL); - } - } - } - else - { - if ( player->pipeline->audiobin ) - { - GstElement *sink_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst; - - /* Set to Avsysaudiosink element */ - if ( sink_element ) - { - gint vol_value = 0; - gboolean mute = FALSE; - vol_value = volume.level[0]; - - g_object_set(G_OBJECT(sink_element), "tuningvolume", vol_value, NULL); - - mute = (vol_value == 0)? TRUE:FALSE; - - g_object_set(G_OBJECT(sink_element), "mute", mute, NULL); - } - - } - } - - MMPLAYER_FLEAVE(); - - return error; -} - gboolean __mmplayer_dump_pipeline_state( mm_player_t* player ) { diff --git a/src/mm_player_streaming.c b/src/mm_player_streaming.c index 9769751..9525d7f 100755 --- a/src/mm_player_streaming.c +++ b/src/mm_player_streaming.c @@ -132,6 +132,7 @@ void __mm_player_streaming_initialize (mm_player_streaming_t* streamer) streamer->is_buffering = FALSE; streamer->is_buffering_done = FALSE; + streamer->is_adaptive_streaming = FALSE; streamer->buffering_percent = -1; MMPLAYER_FLEAVE(); @@ -163,6 +164,8 @@ void __mm_player_streaming_deinitialize (mm_player_streaming_t* streamer) streamer->is_buffering = FALSE; streamer->is_buffering_done = FALSE; + streamer->is_adaptive_streaming = FALSE; + streamer->buffering_percent = -1; MMPLAYER_FLEAVE(); @@ -442,14 +445,14 @@ streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guin buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle); g_object_set (G_OBJECT(buffer_handle->buffer), - "max-size-bytes", MAX_DECODEBIN_BUFFER_BYTES, // fixed + "max-size-bytes", GET_MAX_BUFFER_BYTES(streamer), /* mq size is fixed, control it with high/low percent value*/ "max-size-time", ((guint)ceil(buffering_time) * GST_SECOND), "max-size-buffers", 0, NULL); // disable buffer_handle->buffering_time = buffering_time; - buffer_handle->buffering_bytes = MAX_DECODEBIN_BUFFER_BYTES; + buffer_handle->buffering_bytes = GET_MAX_BUFFER_BYTES(streamer); - debug_log("[New][MQ] max-size-time : %f", buffering_time); + debug_log("max-size-time : %f", buffering_time); } else // queue2 { @@ -558,7 +561,6 @@ void __mm_player_streaming_sync_property(mm_player_streaming_t* streamer, GstEle void __mm_player_streaming_set_multiqueue( mm_player_streaming_t* streamer, GstElement* buffer, gboolean use_buffering, - guint buffering_bytes, gdouble buffering_time, gdouble low_percent, gdouble high_percent) @@ -594,14 +596,14 @@ void __mm_player_streaming_set_multiqueue( mm_player_streaming_t* streamer, if (pre_buffering_time <= 0.0) { - pre_buffering_time = DEFAULT_PLAYING_TIME; + pre_buffering_time = GET_DEFAULT_PLAYING_TIME(streamer); streamer->buffering_req.initial_second = (gint)ceil(buffering_time); } - high_percent = (pre_buffering_time * 100) / MAX_DECODEBIN_BUFFER_TIME; + high_percent = (pre_buffering_time * 100) / GET_MAX_BUFFER_TIME(streamer); debug_log ("high_percent : per %2.3f %%\n", high_percent); - streaming_set_buffer_size (streamer, BUFFER_TYPE_DEMUXED, MAX_DECODEBIN_BUFFER_BYTES, MAX_DECODEBIN_BUFFER_TIME); + streaming_set_buffer_size (streamer, BUFFER_TYPE_DEMUXED, GET_MAX_BUFFER_BYTES(streamer), GET_MAX_BUFFER_TIME(streamer)); streaming_set_buffer_percent (streamer, BUFFER_TYPE_DEMUXED, low_percent, 0, high_percent); streamer->need_sync = TRUE; -- 2.7.4