static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
-static gboolean __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs);
+static gboolean __mmplayer_update_duration_value(mm_player_t *player);
static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
}
if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
- has_duration = __mmplayer_update_duration_attrs(player, attrs);
+ has_duration = __mmplayer_update_duration_value(player);
if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
/* in case of exporting video frame, it requires the 360 video filter.
* it will be handled in _no_more_pads(). */
- if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)){
+ if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
__mmplayer_gst_make_fakesink(player, pad, name);
goto DONE;
}
__mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
+ gint prebuffer_ms = 0, rebuffer_ms = 0;
+
player->streamer = __mm_player_streaming_create();
__mm_player_streaming_initialize(player->streamer, TRUE);
+
+ mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
+ mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
+
+ if (prebuffer_ms > 0) {
+ prebuffer_ms = MAX(prebuffer_ms, 1000);
+ player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
+ }
+
+ if (rebuffer_ms > 0) {
+ player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
+ rebuffer_ms = MAX(rebuffer_ms, 1000);
+ player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
+ }
+
+ LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
+ player->streamer->buffering_req.rebuffer_time);
}
/* realize pipeline */
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
+ if (g_strrstr(player->type, "video/mpegts"))
+ __mmplayer_update_duration_value(player);
+
*duration = player->duration;
return ret;
}
player->streamer->is_adaptive_streaming = TRUE;
}
- if (player->streamer->is_adaptive_streaming) {
+ /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
+ if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
- if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) /* if user did not set the rebuffer value */
- player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
+ if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
+ if (player->streamer->is_adaptive_streaming)
+ player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
+ else
+ player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
+ }
}
LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
return NULL;
}
- /* NOTE : in case of ts streaming, player could not get the correct duration info *
- * skip the pull mode(file or ring buffering) setting. */
- if (g_strrstr(player->type, "video/mpegts"))
- return queue2;
-
if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
+ /* NOTE : in case of ts streaming, player could not get the correct duration info *
+ * skip the pull mode(file or ring buffering) setting. */
if (dur_bytes > 0) {
- type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
- player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
+ if (!g_strrstr(player->type, "video/mpegts")) {
+ type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
+ player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
+ }
} else {
dur_bytes = 0;
}
queue2,
FALSE,
type,
- (guint64)dur_bytes);
+ (guint64)dur_bytes); /* no meaning at the moment */
return queue2;
}
}
int
- _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
+_mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
{
int result = MM_ERROR_NONE;
mm_player_t *player = NULL;
}
int
-_mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
+_mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
{
int ret = MM_ERROR_NONE;
mm_player_t *player = (mm_player_t *)hplayer;
+ MMHandleType attrs = 0;
MMPLAYER_FENTER();
MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
+ MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
- if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
- LOGW("buffer_ms will not be applied.");
-
- LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
-
- if (player->streamer == NULL) {
- player->streamer = __mm_player_streaming_create();
- __mm_player_streaming_initialize(player->streamer, TRUE);
- }
-
- if (buffer_ms >= 0)
- player->streamer->buffering_req.prebuffer_time = buffer_ms;
+ attrs = MMPLAYER_GET_ATTRS(player);
+ MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
- if (rebuffer_ms >= 0)
- player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
+ mm_attrs_get_int_by_name(attrs, MM_PLAYER_PREBUFFER_MS, prebuffer_ms);
+ mm_attrs_get_int_by_name(attrs, MM_PLAYER_REBUFFER_MS, rebuffer_ms);
- MMPLAYER_FLEAVE();
- return ret;
+ LOGD("attr buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
-}
+ if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
+ /* set the platform default (3000 ms) value */
+ if (*prebuffer_ms <= MIN_BUFFERING_TIME)
+ *prebuffer_ms = DEFAULT_PREBUFFERING_TIME;
-int
-_mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
-{
- int ret = MM_ERROR_NONE;
- mm_player_t *player = (mm_player_t *)hplayer;
+ return ret;
+ }
- MMPLAYER_FENTER();
- MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
- MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
+ MMPLAYER_RETURN_VAL_IF_FAIL(player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
+ MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
- if (player->streamer == NULL) {
- player->streamer = __mm_player_streaming_create();
- __mm_player_streaming_initialize(player->streamer, TRUE);
- }
+ *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
- *buffer_ms = player->streamer->buffering_req.prebuffer_time;
- *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
+ if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
+ *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
+ else /* live case */
+ *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
- LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
+ LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
MMPLAYER_FLEAVE();
return ret;
}
static gboolean
-__mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
+__mmplayer_update_duration_value(mm_player_t *player)
{
gboolean ret = FALSE;
gint64 dur_nsec = 0;
} streaming_buffer_info_t;
static void streaming_set_buffer_watermark(mm_player_streaming_t *streamer, BufferType type, gdouble high_watermark_byte, gdouble high_watermark_time);
-static void streaming_set_queue2_queue_type(mm_player_streaming_t *streamer, MuxedBufferType type, guint64 content_size);
+static void streaming_set_queue2_queue_type(mm_player_streaming_t *streamer, MuxedBufferType type);
static void streaming_set_buffer_size(mm_player_streaming_t *streamer, BufferType type, guint buffering_bytes, gint buffering_time);
static void streaming_update_buffering_status(mm_player_streaming_t *streamer, GstMessage *buffering_msg, gint64 position);
static void streaming_get_current_bitrate_info(mm_player_streaming_t *streamer,
void __mm_player_streaming_set_content_bitrate(
mm_player_streaming_t *streamer, guint max_bitrate, guint avg_bitrate)
{
- MMPLAYER_FENTER();
+ gboolean is_update = FALSE;
+ MMPLAYER_FENTER();
MMPLAYER_RETURN_IF_FAIL(streamer);
/* Note : Update buffering criterion bytes
* 3. if there are no updated bitrate, use default buffering limit.
*/
if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate) {
- LOGD("set maximum bitrate(%dbps).", max_bitrate);
+ is_update = TRUE;
streamer->buffer_max_bitrate = max_bitrate;
- if (streamer->buffering_req.is_pre_buffering == FALSE) {
- streamer->need_update = TRUE;
- } else {
- LOGD("pre-buffering...");
-
- if (IS_MUXED_BUFFERING_MODE(streamer))
- streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
- }
}
if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate) {
- LOGD("set average bitrate(%dbps).", avg_bitrate);
+ is_update = TRUE;
streamer->buffer_avg_bitrate = avg_bitrate;
+ }
- if (streamer->buffering_req.is_pre_buffering == FALSE) {
- streamer->need_update = TRUE;
- } else {
- LOGD("pre-buffering...");
-
+ if (is_update) {
+ if (streamer->buffering_req.is_pre_buffering) {
+ /* have to recalc queue2 size value after getting bitrate information */
if (IS_MUXED_BUFFERING_MODE(streamer))
streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
+ } else {
+ streamer->need_update = TRUE;
}
}
return;
}
+static gdouble streaming_get_min_watermark(gdouble high_watermark, gint max_size_time)
+{
+ gdouble min_threshold = 0.05; /* 5% of buffer size */
+ gdouble max_threshold = 0.1; /* 10% of buffer size */
+ gdouble low_watermark = 0.0;
+
+ if (max_size_time > 0)
+ min_threshold = (gdouble)500 / max_size_time; /* watermark for 500 ms */
+
+ low_watermark = high_watermark / 10; /* 10% of hig_watermark */
+
+ LOGD("threshold [%1.3f ~ %1.3f] watermakr[%1.3f ~ %1.3f]",
+ min_threshold, max_threshold, low_watermark, high_watermark);
+
+ low_watermark = MAX(low_watermark, min_threshold);
+ low_watermark = MIN(low_watermark, max_threshold);
+
+ return low_watermark;
+}
+
static void streaming_set_buffer_watermark(mm_player_streaming_t *streamer,
BufferType type, gdouble high_watermark_byte, gdouble high_watermark_time)
{
GST_ELEMENT_NAME(buffer_handle->buffer), high_watermark);
if ((high_watermark == DEFAULT_BUFFER_HIGH_WATERMARK) ||
- (buffer_handle->buffer_high_watermark != high_watermark))
- g_object_set(G_OBJECT(buffer_handle->buffer), "high-watermark", high_watermark, NULL);
+ (buffer_handle->buffer_high_watermark != high_watermark)) {
+ gdouble low_watermark = 0.0;
+
+ /* if the low_watermark is too small, it can cause the underflow issue. */
+ low_watermark = streaming_get_min_watermark(high_watermark, ((type == BUFFER_TYPE_MUXED) ? (0) : (buffer_handle->buffering_time)));
+
+ LOGD("target buffer elem : %s ( %1.3f ~ %1.3f)",
+ GST_ELEMENT_NAME(buffer_handle->buffer), low_watermark, high_watermark);
+
+ g_object_set(G_OBJECT(buffer_handle->buffer), "high-watermark", high_watermark,
+ "low-watermark", low_watermark, NULL);
+ }
buffer_handle->buffer_high_watermark = high_watermark;
return;
}
-static void streaming_set_queue2_queue_type(mm_player_streaming_t *streamer,
- MuxedBufferType type, guint64 content_size)
+static void streaming_set_queue2_queue_type(mm_player_streaming_t *streamer, MuxedBufferType type)
{
streaming_buffer_t *buffer_handle = NULL;
guint64 buffer_size = 0; /* bytes */
buffer_handle->buffering_time = buffering_time;
buffer_handle->buffering_bytes = MAX_BUFFER_SIZE_BYTES;
- LOGD("max-size-time : %d ms", buffering_time);
+ LOGD("byte: %d, max-size-time : %d ms", buffering_bytes, buffering_time);
} else {
/* queue2 */
if (buffer_handle->is_live)
buffer_handle->buffering_bytes = buffering_bytes;
buffer_handle->buffering_time = buffering_time;
- LOGD("max-size-bytes : %d", buffering_bytes);
+ LOGD("max-size-bytes : %d, time : %d", buffering_bytes, buffering_time);
}
}
streamer->buffer_handle[BUFFER_TYPE_MUXED].is_live = TRUE;
}
- queue_size_bytes = (guint)(streamer->buffering_req.prebuffer_time / 1000) * ESTIMATED_BUFFER_UNIT;
+ /* keep estimated value till the pipeline share the bitrate information */
+ queue_size_bytes = (guint)(streamer->buffering_req.prebuffer_time / 1000) * ESTIMATED_BUFFER_UNIT; /* temp size */
queue_size_bytes = MAX(queue_size_bytes, DEFAULT_BUFFER_SIZE_BYTES);
+ queue_size_time = streamer->buffering_req.prebuffer_time;
} else {
if (type >= MUXED_BUFFER_TYPE_MAX) {
LOGE("invalid queue type");
/* set the simple queue size */
queue_size_bytes = DEFAULT_BUFFER_SIZE_BYTES;
- streaming_set_queue2_queue_type(streamer, type, content_size);
+ streaming_set_queue2_queue_type(streamer, type);
+ queue_size_time = 0; /* set in case of use-buffering */
}
- /* queue_size_time will set to queue2 only in case of live buffering. */
- queue_size_time = streamer->buffering_req.prebuffer_time;
-
g_object_set(G_OBJECT(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), "use-buffering", use_buffering, NULL);
LOGD("buffer time: %d ms, buffer bytes: %d", queue_size_time, queue_size_bytes);
void __mm_player_streaming_sync_property(mm_player_streaming_t *streamer, GstElement *decodebin)
{
streaming_buffer_t *buffer_handle = NULL;
+ gdouble low_watermark = 0.0;
MMPLAYER_FENTER();
-
MMPLAYER_RETURN_IF_FAIL(streamer && decodebin);
+ if ((!streamer->need_sync) || (streamer->streaming_buffer_type != BUFFER_TYPE_DEMUXED)) {
+ streamer->need_sync = FALSE;
+ return;
+ }
+
buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
+ low_watermark = streaming_get_min_watermark(buffer_handle->buffer_high_watermark, buffer_handle->buffering_time);
- if ((streamer->need_sync) && (streamer->streaming_buffer_type == BUFFER_TYPE_DEMUXED)) {
- g_object_set(G_OBJECT(decodebin),
- "max-size-bytes", buffer_handle->buffering_bytes,
- "max-size-time", (guint64)(buffer_handle->buffering_time * GST_MSECOND),
- "high-percent", (gint)(buffer_handle->buffer_high_watermark * 100), NULL);
- }
+ g_object_set(G_OBJECT(decodebin),
+ "max-size-bytes", buffer_handle->buffering_bytes,
+ "max-size-time", (guint64)(buffer_handle->buffering_time * GST_MSECOND),
+ "high-percent", (gint)(buffer_handle->buffer_high_watermark * 100),
+ "low-percent", (gint)(low_watermark * 100), NULL);
streamer->need_sync = FALSE;
}
if (streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
- high_watermark = (gdouble)(streamer->buffering_req.prebuffer_time * 100) / MAX_BUFFER_SIZE_TIME;
- LOGD("high_watermark %1.3f %%", high_watermark);
+ high_watermark = (gdouble)(streamer->buffering_req.prebuffer_time) / MAX_BUFFER_SIZE_TIME;
+ LOGD("new pre buffer time %d ms, high_watermark %1.3f %%", streamer->buffering_req.prebuffer_time, high_watermark);
/* initial setting */
streaming_set_buffer_size(streamer, BUFFER_TYPE_DEMUXED, MAX_BUFFER_SIZE_BYTES, MAX_BUFFER_SIZE_TIME);
LOGD("(avg)content_max_byte_rate %d, byte_out_rate %d", buffer_criteria, out_rate);
} else {
- LOGW("There is no content bitrate information");
+ LOGW("There is no content bitrate information, use estimated value");
+ out_rate = estimated_content_bitrate;
}
if ((in_rate > 0) && (out_rate > 0))
}
static void streaming_handle_fixed_buffering_mode(mm_player_streaming_t *streamer,
- gint byte_out_rate, gint fixed_buffering_time, streaming_buffer_info_t *buffer_info)
+ gint byte_out_rate, gint expected_play_time, streaming_buffer_info_t *buffer_info)
{
streaming_buffer_t *buffer_handle = NULL;
- guint buffering_bytes = 0;
- gint buffering_time = 0;
+ guint expected_play_bytes = 0;
gdouble wm_byte = 0.0;
gdouble wm_time = 0.0;
MMPLAYER_RETURN_IF_FAIL(buffer_info);
buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
- buffering_time = fixed_buffering_time;
- LOGD("buffering time: %d ms, out rate: %d", buffering_time, byte_out_rate);
+ LOGD("buffering time: %d ms, out rate: %d", expected_play_time, byte_out_rate);
- if ((buffering_time > 0) && (byte_out_rate > 0)) {
+ if (byte_out_rate > 0) {
guint max_size_byte = GET_MAX_BYTE_BUFFER_SIZE(streamer->streaming_buffer_type);
- buffering_bytes = (guint)GET_NEW_BUFFERING_BYTE((gdouble)(byte_out_rate * buffering_time) / 1000, max_size_byte);
+ expected_play_bytes = (guint)GET_NEW_BUFFERING_BYTE((gdouble)(byte_out_rate * expected_play_time) / 1000, max_size_byte);
} else {
- if (buffering_time <= 0)
- buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
-
LOGW("content bitrate is not updated yet.");
- buffering_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle);
+ expected_play_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle);
}
- GET_WATERMARK(buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_watermark, wm_time);
- GET_WATERMARK(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_watermark, wm_byte);
+ GET_WATERMARK(expected_play_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_watermark, wm_time);
+ GET_WATERMARK(expected_play_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_watermark, wm_byte);
- LOGD("bytes %d, time %d, wm_byte %f, wm_time %f", buffering_bytes, buffering_time, wm_byte, wm_time);
+ LOGD("bytes %d, time %d, wm_byte %f, wm_time %f", expected_play_bytes, expected_play_time, wm_byte, wm_time);
- (*buffer_info).buffering_bytes = buffering_bytes;
- (*buffer_info).buffering_time = buffering_time;
+ (*buffer_info).buffering_bytes = expected_play_bytes;
+ (*buffer_info).buffering_time = expected_play_time;
(*buffer_info).watermark_byte = wm_byte;
(*buffer_info).watermark_time = wm_time;
}