4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
24 #include "mm_player_utils.h"
25 #include "mm_player_streaming.h"
27 #define ESTIMATED_BUFFER_UNIT (1 * 1024 * 1024) /* 1 MBytes */
30 gint byte_in_rate; // byte
31 gint byte_out_rate; // byte
33 } streaming_bitrate_info_t;
36 gint64 position; // ns
37 gint64 duration; // ns
38 guint64 content_size; // bytes
39 } streaming_content_info_t;
42 guint buffering_bytes; // bytes
43 gint buffering_time; // ms
44 gdouble low_watermark;
45 gdouble high_watermark;
46 } streaming_buffer_info_t;
49 __streaming_update_buffer_setting(mmplayer_streaming_t *streamer,
50 GstMessage *buffering_msg,
55 mmplayer_streaming_t *_mm_player_streaming_create(void)
57 mmplayer_streaming_t *streamer = NULL;
61 streamer = (mmplayer_streaming_t *)g_try_malloc0(sizeof(mmplayer_streaming_t));
63 LOGE("fail to create streaming player handle..");
72 static void __streaming_buffer_initialize(streaming_buffer_t *buffer_handle, gboolean buffer_init)
75 buffer_handle->buffer = NULL;
77 buffer_handle->buffering_bytes = DEFAULT_BUFFER_SIZE_BYTES;
78 buffer_handle->buffering_time = DEFAULT_BUFFERING_TIME;
79 buffer_handle->buffer_high_watermark = DEFAULT_BUFFER_HIGH_WATERMARK;
80 buffer_handle->buffer_low_watermark = DEFAULT_BUFFER_LOW_WATERMARK;
81 buffer_handle->is_live = FALSE;
84 void _mm_player_streaming_initialize(mmplayer_streaming_t *streamer, gboolean buffer_init)
87 MMPLAYER_RETURN_IF_FAIL(streamer);
89 streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT;
91 __streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), buffer_init);
92 __streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), buffer_init);
94 streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
95 streamer->buffering_req.is_pre_buffering = TRUE;
96 streamer->buffering_req.prebuffer_time = 0;
97 streamer->buffering_req.rebuffer_time = 0;
99 streamer->default_val.buffering_monitor = FALSE;
100 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
102 streamer->buffer_avg_bitrate = 0;
103 streamer->buffer_max_bitrate = 0;
104 streamer->need_update = FALSE;
105 streamer->need_sync = FALSE;
107 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
108 streamer->is_adaptive_streaming = FALSE;
110 streamer->buffering_percent = -1;
111 streamer->ring_buffer_size = DEFAULT_RING_BUFFER_SIZE_BYTES;
117 void _mm_player_streaming_destroy(mmplayer_streaming_t *streamer)
121 MMPLAYER_FREEIF(streamer);
128 void _mm_player_streaming_set_content_bitrate(
129 mmplayer_streaming_t *streamer, guint max_bitrate, guint avg_bitrate)
131 gboolean is_update = FALSE;
134 MMPLAYER_RETURN_IF_FAIL(streamer);
136 if (max_bitrate > 0 && max_bitrate != streamer->buffer_max_bitrate) {
138 streamer->buffer_max_bitrate = max_bitrate;
141 if (avg_bitrate > 0 && avg_bitrate != streamer->buffer_avg_bitrate) {
143 streamer->buffer_avg_bitrate = avg_bitrate;
147 if (streamer->buffering_req.is_pre_buffering) {
148 /* have to recalc queue2 size value after getting bitrate information */
149 if (IS_MUXED_BUFFERING_MODE(streamer))
150 __streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
152 streamer->need_update = TRUE;
160 static void __streaming_calc_watermark(mmplayer_streaming_t *streamer,
161 guint expected_play_bytes, gint expected_play_time, gdouble *low_wm, gdouble *high_wm)
163 #define PORTION_OF_HIGH_WM 1.1 /* need to compensate about low level */
164 #define PORTION_OF_LOW_WM 0.1
166 streaming_buffer_t *buffer_handle = NULL;
167 gdouble wm_byte = 0.0, wm_time = 0.0;
168 gint current_buffering_size = 0;
170 MMPLAYER_RETURN_IF_FAIL(streamer && low_wm && high_wm);
172 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
174 LOGD("type %d, bytes %d / %d, time %d / %d", streamer->streaming_buffer_type,
175 expected_play_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle),
176 expected_play_time, GET_CURRENT_BUFFERING_TIME(buffer_handle));
178 if (expected_play_bytes > 0) {
179 /* and buffer size will be increased */
180 current_buffering_size = MAX(GET_CURRENT_BUFFERING_BYTE(buffer_handle), (expected_play_bytes * PORTION_OF_HIGH_WM));
181 GET_WATERMARK((expected_play_bytes * PORTION_OF_HIGH_WM), current_buffering_size, buffer_handle->buffer_high_watermark, wm_byte);
182 wm_byte = MIN(wm_byte, DEFAULT_BUFFER_HIGH_WATERMARK);
185 if (IS_MUXED_BUFFERING_MODE(streamer)) {
187 *low_wm = wm_byte * PORTION_OF_LOW_WM;
189 /* If user set the very low level buffering time,
190 buffer underrun could be occurred even if the min range is considered. */
191 GET_VALID_VALUE((*low_wm), LOW_WATERMARK_MIN_BYTE_LEVEL, DEFAULT_BUFFER_LOW_WATERMARK);
193 gdouble prev_low_wm_time = 0.0;
194 gdouble low_wm_time = 0.0, high_wm_time = 0.0;
196 expected_play_time = MAX(expected_play_time, LOW_WATERMARK_MIN_TIME_VALUE);
197 low_wm_time = expected_play_time * PORTION_OF_LOW_WM;
198 high_wm_time = expected_play_time * PORTION_OF_HIGH_WM;
200 /* 1. Get min watermark value */
201 /* 1-1. get max buffer size, expected time could be greater than current one */
202 LOGE("low wm time : %.3f ms", low_wm_time);
203 current_buffering_size = MAX(GET_CURRENT_BUFFERING_TIME(buffer_handle), high_wm_time);
205 /* 1-2. get previous low time value to keep the minimum watermark */
206 prev_low_wm_time = GET_CURRENT_BUFFERING_TIME(buffer_handle) * buffer_handle->buffer_low_watermark;
207 GET_VALID_VALUE(low_wm_time, LOW_WATERMARK_MIN_TIME_VALUE, prev_low_wm_time);
209 /* 1-3. get min watermark value based on the max buffer size */
210 GET_WATERMARK(low_wm_time, current_buffering_size, buffer_handle->buffer_low_watermark, *low_wm);
211 *low_wm = MIN(*low_wm, DEFAULT_BUFFER_LOW_WATERMARK);
213 /* 2. Get high watermark value.
214 If the expected time is greater than current one, the buffer size will be increased after */
215 GET_WATERMARK(high_wm_time, current_buffering_size, buffer_handle->buffer_high_watermark, wm_time);
216 *high_wm = MAX(wm_byte, wm_time);
217 *high_wm = MIN(*high_wm, DEFAULT_BUFFER_HIGH_WATERMARK);
220 if (*low_wm >= *high_wm) {
221 LOGW("invalid high wm value %1.3f", *high_wm);
222 *high_wm = DEFAULT_BUFFER_HIGH_WATERMARK;
225 LOGD("new watermark value [%f ~ %f]", *low_wm, *high_wm);
228 static void __streaming_set_buffer_watermark(mmplayer_streaming_t *streamer,
229 buffer_type_e type, gdouble low_watermark, gdouble high_watermark)
231 streaming_buffer_t *buffer_handle = NULL;
232 gchar *factory_name = NULL;
235 MMPLAYER_RETURN_IF_FAIL(streamer);
236 MMPLAYER_RETURN_IF_FAIL(type < BUFFER_TYPE_MAX);
238 buffer_handle = &(streamer->buffer_handle[type]);
239 if (!(buffer_handle && buffer_handle->buffer)) {
240 LOGE("buffer_handle->buffer is NULL!");
244 factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer));
247 LOGE("Fail to get factory name!");
251 if (high_watermark <= MIN_BUFFER_WATERMARK || high_watermark >= MAX_BUFFER_WATERMARK)
252 high_watermark = DEFAULT_BUFFER_HIGH_WATERMARK;
254 if (low_watermark <= MIN_BUFFER_WATERMARK || low_watermark >= MAX_BUFFER_WATERMARK)
255 low_watermark = DEFAULT_BUFFER_LOW_WATERMARK;
257 /* if use-buffering is disabled, this settings do not have any meaning. */
258 if ((high_watermark == DEFAULT_BUFFER_HIGH_WATERMARK) ||
259 (buffer_handle->buffer_high_watermark != high_watermark) ||
260 (buffer_handle->buffer_low_watermark != low_watermark))
261 g_object_set(G_OBJECT(buffer_handle->buffer), "high-watermark", high_watermark,
262 "low-watermark", low_watermark, NULL);
264 LOGD("update elem:%s, wm:%1.3f ~ %1.3f", GST_ELEMENT_NAME(buffer_handle->buffer), low_watermark, high_watermark);
266 buffer_handle->buffer_high_watermark = high_watermark;
267 buffer_handle->buffer_low_watermark = low_watermark;
273 static void __streaming_set_queue2_queue_type(mmplayer_streaming_t *streamer, muxed_buffer_type_e type)
275 streaming_buffer_t *buffer_handle = NULL;
276 guint64 buffer_size = 0; /* bytes */
279 MMPLAYER_RETURN_IF_FAIL(streamer);
280 MMPLAYER_RETURN_IF_FAIL(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer);
282 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_MUXED]);
284 if (type == MUXED_BUFFER_TYPE_MEM_QUEUE) { /* ts */
285 LOGD("use memory queue for buffering. streaming is played on push-based. \n"
286 "buffering position would not be updated.\n"
287 "buffered data would be flushed after played.\n"
288 "seeking and getting duration could be failed due to file format.");
292 /* @see ini->http_ring_buffer_size */
293 buffer_size = (guint64)((streamer->ring_buffer_size > 0) ? (streamer->ring_buffer_size) : DEFAULT_RING_BUFFER_SIZE_BYTES);
295 LOGW("ring buffer size: %"G_GUINT64_FORMAT, buffer_size);
296 g_object_set(G_OBJECT(buffer_handle->buffer), "ring-buffer-max-size", buffer_size, NULL);
302 static void __streaming_set_buffer_size(mmplayer_streaming_t *streamer,
303 buffer_type_e type, guint buffering_bytes, gint buffering_time)
305 streaming_buffer_t *buffer_handle = NULL;
309 MMPLAYER_RETURN_IF_FAIL(streamer);
310 MMPLAYER_RETURN_IF_FAIL(buffering_bytes > 0);
311 MMPLAYER_RETURN_IF_FAIL(type < BUFFER_TYPE_MAX);
313 buffer_handle = &(streamer->buffer_handle[type]);
315 if (buffer_handle && buffer_handle->buffer) {
316 if (g_strrstr(GST_ELEMENT_NAME(buffer_handle->buffer), "multiqueue")) {
317 if (buffering_time <= 0)
318 buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
320 g_object_set(G_OBJECT(buffer_handle->buffer),
321 "max-size-bytes", MAX_BUFFER_SIZE_BYTES, /* mq size is fixed, control it with high/low watermark value*/
322 "max-size-time", (guint64)(buffering_time * GST_MSECOND),
323 "max-size-buffers", 0, /* disable */
324 "use-interleave", FALSE, NULL);
326 GET_CURRENT_BUFFERING_TIME(buffer_handle) = buffering_time;
327 GET_CURRENT_BUFFERING_BYTE(buffer_handle) = MAX_BUFFER_SIZE_BYTES;
329 LOGD("byte: %d, max-size-time : %d ms", buffering_bytes, buffering_time);
332 if (buffer_handle->is_live)
333 g_object_set(G_OBJECT(buffer_handle->buffer),
334 "max-size-bytes", buffering_bytes,
335 "max-size-time", (guint64)(buffering_time * GST_MSECOND),
336 "max-size-buffers", 0,
337 "use-rate-estimate", TRUE, NULL);
339 g_object_set(G_OBJECT(buffer_handle->buffer),
340 "max-size-bytes", buffering_bytes,
341 "max-size-time", (guint64)0,
342 "max-size-buffers", 0,
343 "use-rate-estimate", FALSE, NULL);
345 GET_CURRENT_BUFFERING_BYTE(buffer_handle) = buffering_bytes;
346 GET_CURRENT_BUFFERING_TIME(buffer_handle) = buffering_time;
348 LOGD("max-size-bytes : %d, time : %d", buffering_bytes, buffering_time);
356 void _mm_player_streaming_set_queue2(mmplayer_streaming_t *streamer, GstElement *buffer,
357 gboolean use_buffering, muxed_buffer_type_e type, guint64 content_size)
359 guint queue_size_bytes = 0;
360 guint queue_size_time = 0;
363 MMPLAYER_RETURN_IF_FAIL(streamer && buffer);
365 LOGD("use buffering %d, type %d, content_size %"G_GUINT64_FORMAT, use_buffering, type, content_size);
367 streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer = buffer;
369 if (use_buffering) { /* audio only content use queue2 for buffering */
370 streamer->streaming_buffer_type = BUFFER_TYPE_MUXED;
372 if (streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
373 streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
375 if (content_size == 0) {
376 LOGD("live streaming without mq");
377 streamer->buffer_handle[BUFFER_TYPE_MUXED].is_live = TRUE;
380 /* keep estimated value till the pipeline share the bitrate information */
381 queue_size_bytes = (guint)(streamer->buffering_req.prebuffer_time / 1000) * ESTIMATED_BUFFER_UNIT; /* temp size */
382 queue_size_bytes = MAX(queue_size_bytes, DEFAULT_BUFFER_SIZE_BYTES);
383 queue_size_time = streamer->buffering_req.prebuffer_time;
385 if (type >= MUXED_BUFFER_TYPE_MAX) {
386 LOGE("invalid queue type");
390 /* set the simple queue size */
391 queue_size_bytes = DEFAULT_BUFFER_SIZE_BYTES;
392 __streaming_set_queue2_queue_type(streamer, type);
393 queue_size_time = 0; /* set in case of use-buffering */
396 g_object_set(G_OBJECT(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), "use-buffering", use_buffering, NULL);
398 LOGD("buffer time: %d ms, buffer bytes: %d", queue_size_time, queue_size_bytes);
399 __streaming_set_buffer_size(streamer, BUFFER_TYPE_MUXED, queue_size_bytes, queue_size_time);
400 __streaming_set_buffer_watermark(streamer, BUFFER_TYPE_MUXED, DEFAULT_BUFFER_LOW_WATERMARK, DEFAULT_BUFFER_HIGH_WATERMARK);
406 void _mm_player_streaming_sync_property(mmplayer_streaming_t *streamer, GstElement *decodebin)
408 streaming_buffer_t *buffer_handle = NULL;
411 MMPLAYER_RETURN_IF_FAIL(streamer && decodebin);
413 if ((!streamer->need_sync) || (streamer->streaming_buffer_type != BUFFER_TYPE_DEMUXED)) {
414 streamer->need_sync = FALSE;
418 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
420 LOGD("sync : %1.3f ~ %1.3f", buffer_handle->buffer_low_watermark, buffer_handle->buffer_high_watermark);
421 g_object_set(G_OBJECT(decodebin),
422 "max-size-bytes", GET_CURRENT_BUFFERING_BYTE(buffer_handle),
423 "max-size-time", (guint64)(GET_CURRENT_BUFFERING_TIME(buffer_handle) * GST_MSECOND),
424 "high-percent", (gint)(buffer_handle->buffer_high_watermark * 100),
425 "low-percent", (gint)(buffer_handle->buffer_low_watermark * 100), NULL);
427 streamer->need_sync = FALSE;
430 void _mm_player_streaming_set_multiqueue(mmplayer_streaming_t *streamer, GstElement *buffer)
432 streaming_buffer_t *buffer_handle = NULL;
433 gdouble high_wm = 0.0, low_wm = 0.0;
436 MMPLAYER_RETURN_IF_FAIL(streamer && buffer);
438 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
439 buffer_handle->buffer = buffer;
441 LOGD("pre_buffering: %d ms", streamer->buffering_req.prebuffer_time);
443 streamer->streaming_buffer_type = BUFFER_TYPE_DEMUXED;
444 g_object_set(G_OBJECT(buffer_handle->buffer), "use-buffering", TRUE, NULL);
446 if (streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
447 streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
449 /* initial setting */
450 __streaming_set_buffer_size(streamer, BUFFER_TYPE_DEMUXED, MAX_BUFFER_SIZE_BYTES, MAX_BUFFER_SIZE_TIME);
452 __streaming_calc_watermark(streamer, 0, streamer->buffering_req.prebuffer_time, &low_wm, &high_wm);
453 __streaming_set_buffer_watermark(streamer, BUFFER_TYPE_DEMUXED, low_wm, high_wm);
455 streamer->need_sync = TRUE;
461 static void __streaming_get_current_bitrate_info(mmplayer_streaming_t *streamer,
462 GstMessage *buffering_msg, streaming_content_info_t content_info, streaming_bitrate_info_t *bitrate_info)
464 GstQuery *query = NULL;
465 GstBufferingMode mode = GST_BUFFERING_STREAM;
468 gint64 buffering_left = -1;
470 guint estimated_content_bitrate = 0;
472 gint buffer_buffering_time = DEFAULT_BUFFERING_TIME;
476 MMPLAYER_RETURN_IF_FAIL(streamer);
477 MMPLAYER_RETURN_IF_FAIL(bitrate_info);
479 if ((buffering_msg == NULL) ||
480 ((streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer != NULL) &&
481 (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer != NULL) &&
482 (buffering_msg->src == (GstObject *)streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer))) {
483 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
485 if (gst_element_query((streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), query))
486 gst_query_parse_buffering_stats(query, &mode, &in_rate, &out_rate, &buffering_left);
487 gst_query_unref(query);
489 gst_message_parse_buffering_stats(buffering_msg, &mode, &in_rate, &out_rate, &buffering_left);
492 LOGD("Streaming Info : in %d, out %d, left %"G_GINT64_FORMAT, in_rate, out_rate, buffering_left);
494 if ((content_info.content_size > 0) && (content_info.duration > 0) && ((content_info.duration / GST_SECOND) > 0))
495 estimated_content_bitrate = GET_BIT_FROM_BYTE((guint)(content_info.content_size / (content_info.duration / GST_SECOND)));
497 if (streamer->buffer_max_bitrate > 0) {
498 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, streamer->buffer_avg_bitrate);
499 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, estimated_content_bitrate);
502 if (streamer->buffer_avg_bitrate > 0)
503 out_rate = GET_BYTE_FROM_BIT(MAX(streamer->buffer_avg_bitrate, estimated_content_bitrate));
504 else if (estimated_content_bitrate > 0)
505 out_rate = GET_BYTE_FROM_BIT(estimated_content_bitrate);
506 else if (streamer->buffer_max_bitrate > 0)
507 out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate/3);
509 LOGW("There is no content information");
511 LOGD("byte_out_rate %d", out_rate);
513 if ((in_rate > 0) && (out_rate > 0))
514 buffer_buffering_time = (gint)(out_rate / in_rate) * 1000;
515 else if ((in_rate <= 0) && (out_rate > 0))
516 buffer_buffering_time = MAX_BUFFERING_TIME;
518 buffer_buffering_time = DEFAULT_BUFFERING_TIME;
520 (*bitrate_info).byte_in_rate = in_rate;
521 (*bitrate_info).byte_out_rate = out_rate;
522 (*bitrate_info).time_rate = buffer_buffering_time;
525 static void __streaming_handle_fixed_buffering_mode(mmplayer_streaming_t *streamer,
526 gint byte_out_rate, gint expected_play_time, streaming_buffer_info_t *buffer_info)
528 streaming_buffer_t *buffer_handle = NULL;
530 guint expected_play_bytes = 0;
531 gdouble high_wm = 0.0, low_wm = 0.0;
533 MMPLAYER_RETURN_IF_FAIL(streamer);
534 MMPLAYER_RETURN_IF_FAIL(buffer_info);
536 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
538 LOGD("buffering time: %d ms, out rate: %d", expected_play_time, byte_out_rate);
540 if (byte_out_rate > 0) {
541 guint max_size_byte = GET_MAX_BUFFER_SIZE_BYTES(streamer->streaming_buffer_type);
542 expected_play_bytes = (guint)GET_NEW_BUFFERING_BYTE((gdouble)(byte_out_rate * expected_play_time) / 1000, max_size_byte);
544 LOGW("content bitrate is not updated yet.");
545 expected_play_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle);
548 __streaming_calc_watermark(streamer, expected_play_bytes, expected_play_time, &low_wm, &high_wm);
550 (*buffer_info).buffering_bytes = expected_play_bytes;
551 (*buffer_info).buffering_time = expected_play_time;
552 (*buffer_info).high_watermark = high_wm;
553 (*buffer_info).low_watermark = low_wm;
556 static void __streaming_handle_adaptive_buffering_mode(mmplayer_streaming_t *streamer,
557 streaming_content_info_t content_info, streaming_bitrate_info_t bitrate_info,
558 streaming_buffer_info_t *buffer_info, gint expected_play_time)
560 gint buffering_bytes = 0;
561 gint adj_buffering_bytes = 0;
562 gint buffer_buffering_time = 0;
563 gdouble high_wm = 0.0, low_wm = 0.0;
564 gdouble portion = 0.0;
565 gint default_buffering_time = 0;
567 MMPLAYER_RETURN_IF_FAIL(streamer);
568 MMPLAYER_RETURN_IF_FAIL(buffer_info);
570 LOGD("monitor %d, pos %"G_GINT64_FORMAT", dur %"G_GINT64_FORMAT", size %"G_GUINT64_FORMAT", in/out:%d/%d, time_rate:%d, need:%d ms",
571 streamer->default_val.buffering_monitor, content_info.position, content_info.duration, content_info.content_size,
572 bitrate_info.byte_in_rate, bitrate_info.byte_out_rate, bitrate_info.time_rate, expected_play_time);
574 if ((content_info.duration <= 0) ||
575 (content_info.content_size <= 0)) {
576 LOGW("keep previous setting.");
580 if (bitrate_info.byte_out_rate <= 0) {
581 LOGW("keep previous setting.");
585 if (bitrate_info.byte_in_rate < bitrate_info.byte_out_rate) {
586 guint max_size_byte = GET_MAX_BUFFER_SIZE_BYTES(streamer->streaming_buffer_type);
587 portion = (double)(expected_play_time * GST_MSECOND) / (double)content_info.duration;
588 buffering_bytes = GET_NEW_BUFFERING_BYTE(
589 (((double)content_info.content_size * portion) *
590 (1 - (double)bitrate_info.byte_in_rate / (double)bitrate_info.byte_out_rate)), max_size_byte);
592 /* buffering_bytes will be set as streamer->default_val.buffering_time *
593 * receiving rate is bigger than avg content bitrate
594 * so there is no reason to buffering. if the buffering msg is posted
595 * in-rate or contents bitrate has wrong value. */
596 LOGW("don't need to do buffering.");
599 if (buffering_bytes > 0)
600 buffer_buffering_time = (gint)(buffering_bytes / bitrate_info.byte_out_rate) * 1000;
602 if (content_info.position <= 0) {
603 /* if the buffer is filled under 50%, MSL use the original default buffering time.
604 if not, MSL use just 2 sec as a default buffering time. (to reduce initial buffering time) */
605 default_buffering_time = streamer->default_val.buffering_time - ((gdouble)streamer->buffering_percent / 50) * 1000;
607 default_buffering_time = streamer->default_val.buffering_time;
610 if (buffer_buffering_time < default_buffering_time) {
611 guint max_size_byte = GET_MAX_BUFFER_SIZE_BYTES(streamer->streaming_buffer_type);
613 LOGD("adjusted time: %d -> %d ms", buffer_buffering_time, default_buffering_time);
614 LOGD("adjusted bytes : %d or %d", buffering_bytes,
615 (gint)(bitrate_info.byte_out_rate * buffer_buffering_time / 1000));
617 /* start monitoring the abmormal state */
618 if (content_info.position > 0)
619 streamer->default_val.buffering_monitor = TRUE;
621 buffer_buffering_time = default_buffering_time;
622 adj_buffering_bytes = GET_NEW_BUFFERING_BYTE(
623 (bitrate_info.byte_out_rate * (gint)ceil((gdouble)buffer_buffering_time / 1000)), max_size_byte);
624 buffering_bytes = MAX(buffering_bytes, adj_buffering_bytes);
627 __streaming_calc_watermark(streamer, buffering_bytes, buffer_buffering_time, &low_wm, &high_wm);
629 (*buffer_info).buffering_bytes = buffering_bytes;
630 (*buffer_info).buffering_time = buffer_buffering_time;
631 (*buffer_info).high_watermark = high_wm;
632 (*buffer_info).low_watermark = low_wm;
635 static void __streaming_update_buffer_setting(mmplayer_streaming_t *streamer,
636 GstMessage *buffering_msg, guint64 content_size, gint64 position, gint64 duration)
638 streaming_buffer_t *buffer_handle = NULL;
639 mmplayer_buffering_mode_e buffering_mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
640 gint expected_play_time = DEFAULT_REBUFFERING_TIME;
642 streaming_buffer_info_t buffer_info = {0,};
643 streaming_content_info_t content_info = {0,};
644 streaming_bitrate_info_t bitrate_info = {0,};
647 MMPLAYER_RETURN_IF_FAIL(streamer);
649 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
651 if (streamer->buffering_req.is_pre_buffering == TRUE) {
652 buffering_mode = MM_PLAYER_BUFFERING_MODE_FIXED;
653 expected_play_time = streamer->buffering_req.prebuffer_time;
655 if (content_size == 0 || duration == 0) /* can not support adaptive mode */
656 buffering_mode = MM_PLAYER_BUFFERING_MODE_FIXED;
658 buffering_mode = streamer->buffering_req.mode;
660 if (buffering_mode == MM_PLAYER_BUFFERING_MODE_FIXED) {
661 if (streamer->buffering_req.rebuffer_time > 0)
662 expected_play_time = streamer->buffering_req.rebuffer_time;
664 expected_play_time = DEFAULT_LIVE_REBUFFER_TIME;
668 LOGD("buffering mode: %d, time: %d", buffering_mode, expected_play_time);
670 content_info.position = position;
671 content_info.duration = duration;
672 content_info.content_size = content_size;
674 __streaming_get_current_bitrate_info(streamer, buffering_msg, content_info, &bitrate_info);
676 LOGD("in_r:%d, out_r:%d", bitrate_info.byte_in_rate, bitrate_info.byte_out_rate);
678 if (buffering_mode == MM_PLAYER_BUFFERING_MODE_FIXED) {
679 __streaming_handle_fixed_buffering_mode(streamer, bitrate_info.byte_out_rate, expected_play_time, &buffer_info);
681 __streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, expected_play_time);
683 /* even if new byte size is smaller than the previous one, time need to be updated. */
684 if (IS_MUXED_BUFFERING_MODE(streamer))
685 GET_CURRENT_BUFFERING_TIME(buffer_handle) = buffer_info.buffering_time;
688 LOGD("adj buffer(%d) %d->%d bytes/%d->%d ms",
689 streamer->streaming_buffer_type,
690 GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_info.buffering_bytes,
691 GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_info.buffering_time);
693 /* queue2 : bytes, multiqueue : time */
694 if (((GET_CURRENT_BUFFERING_BYTE(buffer_handle) < buffer_info.buffering_bytes) && IS_MUXED_BUFFERING_MODE(streamer)) ||
695 ((GET_CURRENT_BUFFERING_TIME(buffer_handle) < buffer_info.buffering_time) && IS_DEMUXED_BUFFERING_MODE(streamer))) {
696 if (duration > 0 && position > 0) {
697 gint buffering_time_limit = (gint)(duration - position) / GST_MSECOND;
699 if (buffer_info.buffering_time > buffering_time_limit)
700 buffer_info.buffering_time = buffering_time_limit;
702 __streaming_set_buffer_size(streamer, streamer->streaming_buffer_type, buffer_info.buffering_bytes, buffer_info.buffering_time);
705 __streaming_set_buffer_watermark(streamer, streamer->streaming_buffer_type, buffer_info.low_watermark, buffer_info.high_watermark);
707 LOGD("buffer setting: size %d, time %d, watermark %f", GET_CURRENT_BUFFERING_BYTE(buffer_handle),
708 GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_watermark);
710 streamer->need_sync = TRUE;
713 static void __streaming_adjust_min_threshold(mmplayer_streaming_t *streamer, gint64 position)
715 #define DEFAULT_TIME_PAD 1000 /* ms */
716 gint playing_time = 0;
720 MMPLAYER_RETURN_IF_FAIL(streamer);
722 playing_time = (gint)((position - streamer->default_val.prev_pos) / GST_MSECOND);
724 LOGD("buffering monitor = %s", (streamer->default_val.buffering_monitor) ? "ON" : "OFF");
725 LOGD("playing_time (%d ms) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT, playing_time, position, streamer->default_val.prev_pos);
726 LOGD("default time : %d, prev buffering t : %d",
727 streamer->default_val.buffering_time, streamer->buffer_handle[streamer->streaming_buffer_type].buffering_time);
729 if ((streamer->default_val.buffering_monitor) && (playing_time <= streamer->default_val.buffering_time)) {
731 time_gap = streamer->default_val.buffering_time - DEFAULT_BUFFERING_TIME;
733 time_gap = DEFAULT_TIME_PAD;
735 streamer->default_val.buffering_time += time_gap * 2;
736 streamer->default_val.buffering_time = MIN(streamer->default_val.buffering_time, MAX_BUFFERING_TIME);
738 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
741 LOGD("new default min value %d", streamer->default_val.buffering_time);
743 streamer->default_val.buffering_monitor = FALSE;
744 streamer->default_val.prev_pos = position;
747 static void __streaming_update_buffering_status(mmplayer_streaming_t *streamer, GstMessage *buffering_msg, gint64 position)
749 gint buffer_percent = 0;
753 MMPLAYER_RETURN_IF_FAIL(streamer);
754 MMPLAYER_RETURN_IF_FAIL(buffering_msg);
755 MMPLAYER_RETURN_IF_FAIL(GST_IS_MESSAGE(buffering_msg));
756 MMPLAYER_RETURN_IF_FAIL((GST_MESSAGE_TYPE(buffering_msg) == GST_MESSAGE_BUFFERING));
758 /* update when buffering has started. */
759 if (!(streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
760 streamer->buffering_state = MM_PLAYER_BUFFERING_IN_PROGRESS;
761 streamer->buffering_percent = -1;
763 if (!streamer->buffering_req.is_pre_buffering) {
764 streamer->need_update = TRUE;
765 __streaming_adjust_min_threshold(streamer, position);
769 /* update buffer percent */
770 gst_message_parse_buffering(buffering_msg, &buffer_percent);
772 /* LOGD("[%s] buffering per %d%% -> %d%%, state 0x%X", streamer->buffering_percent, buffer_percent, streamer->buffering_state); */
774 if (streamer->buffering_percent < buffer_percent) {
775 LOGD("[%s] buffering %d%%....",
776 GST_OBJECT_NAME(GST_MESSAGE_SRC(buffering_msg)), buffer_percent);
777 streamer->buffering_percent = buffer_percent;
780 if (streamer->buffering_percent == MAX_BUFFER_PERCENT) {
781 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
782 streamer->buffering_req.is_pre_buffering = FALSE;
783 streamer->need_update = TRUE;
784 } else if (streamer->buffering_state & MM_PLAYER_BUFFERING_COMPLETE) {
785 streamer->buffering_state = MM_PLAYER_BUFFERING_COMPLETE; /* have to keep state to ignore remained msg till get 100% msg */
786 streamer->buffering_req.is_pre_buffering = FALSE;
787 streamer->buffering_percent = MAX_BUFFER_PERCENT;
788 LOGD("updated to the buffering 100%%.... (by force)");
792 void _mm_player_streaming_buffering(mmplayer_streaming_t *streamer, GstMessage *buffering_msg,
793 guint64 content_size, gint64 position, gint64 duration)
796 MMPLAYER_RETURN_IF_FAIL(streamer);
799 if (position > (gint64)(streamer->buffering_req.prebuffer_time * GST_MSECOND))
800 streamer->buffering_req.is_pre_buffering = FALSE;
802 __streaming_update_buffering_status(streamer, buffering_msg, position);
804 if (!streamer->need_update)
808 streamer->need_update = FALSE;
809 __streaming_update_buffer_setting(streamer, buffering_msg, content_size, position, duration);