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.
25 #include "mm_player_utils.h"
26 #include "mm_player_streaming.h"
29 gint byte_in_rate; // byte
30 gint byte_out_rate; // byte
32 guint buffer_criteria; // 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
46 } streaming_buffer_info_t;
48 static void streaming_check_buffer_percent(gdouble in_low, gdouble in_high, gdouble *out_low, gdouble *out_high);
49 static void streaming_set_buffer_percent(mm_player_streaming_t* streamer, BufferType type, gdouble low_percent, gdouble high_percent_byte, gdouble high_percent_time);
50 static void streaming_set_queue2_queue_type(mm_player_streaming_t* streamer, MuxedBufferType type, gchar * file_path, guint64 content_size);
51 static void streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gint buffering_time);
52 static void streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position);
53 static void streaming_get_current_bitrate_info(mm_player_streaming_t* streamer,
54 GstMessage *buffering_msg,
55 streaming_content_info_t content_info,
56 streaming_bitrate_info_t* bitrate_info);
58 streaming_handle_fixed_buffering_mode(mm_player_streaming_t* streamer,
60 gint fixed_buffering_time,
61 streaming_buffer_info_t* buffer_info);
63 streaming_handle_adaptive_buffering_mode(mm_player_streaming_t* streamer,
64 streaming_content_info_t content_info,
65 streaming_bitrate_info_t bitrate_info,
66 streaming_buffer_info_t* buffer_info,
67 gint expected_play_time);
69 streaming_update_buffer_setting(mm_player_streaming_t* streamer,
70 GstMessage *buffering_msg,
75 mm_player_streaming_t *
76 __mm_player_streaming_create(void)
78 mm_player_streaming_t *streamer = NULL;
82 streamer = (mm_player_streaming_t *) g_malloc0(sizeof(mm_player_streaming_t));
84 LOGE("fail to create streaming player handle..\n");
94 streaming_buffer_initialize(streaming_buffer_t* buffer_handle, gboolean buffer_init)
97 buffer_handle->buffer = NULL;
99 buffer_handle->buffering_bytes = DEFAULT_BUFFER_SIZE_BYTES;
100 buffer_handle->buffering_time = DEFAULT_BUFFERING_TIME;
101 buffer_handle->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
102 buffer_handle->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
103 buffer_handle->is_live = FALSE;
107 void __mm_player_streaming_initialize(mm_player_streaming_t* streamer)
111 streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue
113 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), TRUE);
114 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), TRUE);
116 streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
117 streamer->buffering_req.is_pre_buffering = FALSE;
118 streamer->buffering_req.prebuffer_time = 0;
119 streamer->buffering_req.rebuffer_time = 0;
121 streamer->default_val.buffering_monitor = FALSE;
122 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
124 streamer->buffer_avg_bitrate = 0;
125 streamer->buffer_max_bitrate = 0;
126 streamer->need_update = FALSE;
127 streamer->need_sync = FALSE;
129 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
130 streamer->is_adaptive_streaming = FALSE;
132 streamer->buffering_percent = -1;
133 streamer->ring_buffer_size = DEFAULT_RING_BUFFER_SIZE;
139 void __mm_player_streaming_deinitialize(mm_player_streaming_t* streamer)
142 MMPLAYER_RETURN_IF_FAIL(streamer);
144 streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue
146 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), FALSE);
147 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), FALSE);
149 streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
150 streamer->buffering_req.is_pre_buffering = FALSE;
151 streamer->buffering_req.prebuffer_time = 0;
152 streamer->buffering_req.rebuffer_time = 0;
154 streamer->default_val.buffering_monitor = FALSE;
155 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
157 streamer->buffer_avg_bitrate = 0;
158 streamer->buffer_max_bitrate = 0;
159 streamer->need_update = FALSE;
160 streamer->need_sync = FALSE;
162 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
163 streamer->is_adaptive_streaming = FALSE;
165 streamer->buffering_percent = -1;
166 streamer->ring_buffer_size = DEFAULT_RING_BUFFER_SIZE;
172 void __mm_player_streaming_destroy(mm_player_streaming_t* streamer)
183 void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate)
187 MMPLAYER_RETURN_IF_FAIL(streamer);
189 /* Note : Update buffering criterion bytes
190 * 1. maximum bitrate is considered first.
191 * 2. average bitrage * 3 is next.
192 * 3. if there are no updated bitrate, use default buffering limit.
194 if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate) {
195 LOGD("set maximum bitrate(%dbps).\n", max_bitrate);
196 streamer->buffer_max_bitrate = max_bitrate;
197 if (streamer->buffering_req.is_pre_buffering == FALSE) {
198 streamer->need_update = TRUE;
200 LOGD("pre-buffering...\n");
202 if (IS_MUXED_BUFFERING_MODE(streamer))
203 streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
207 if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate) {
208 LOGD("set averate bitrate(%dbps).\n", avg_bitrate);
209 streamer->buffer_avg_bitrate = avg_bitrate;
211 if (streamer->buffering_req.is_pre_buffering == FALSE) {
212 streamer->need_update = TRUE;
214 LOGD("pre-buffering...\n");
216 if (IS_MUXED_BUFFERING_MODE(streamer))
217 streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
226 streaming_check_buffer_percent(gdouble in_low, gdouble in_high, gdouble *out_low, gdouble *out_high)
228 gdouble buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
229 gdouble buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
233 MMPLAYER_RETURN_IF_FAIL(out_low && out_high);
235 if (in_low <= MIN_BUFFER_PERCENT || in_low >= MAX_BUFFER_PERCENT)
236 LOGW("buffer low percent is out of range. use defaut value.");
238 buffer_low_percent = in_low;
240 if (in_high <= MIN_BUFFER_PERCENT || in_high >= MAX_BUFFER_PERCENT)
241 LOGW("buffer high percent is out of range. use defaut value.");
243 buffer_high_percent = in_high;
245 if (buffer_high_percent <= buffer_low_percent)
246 buffer_high_percent = buffer_low_percent + 1.0;
248 LOGD("set buffer percent to %2.3f ~ %2.3f.", buffer_low_percent, buffer_high_percent);
250 *out_low = buffer_low_percent;
251 *out_high = buffer_high_percent;
255 streaming_set_buffer_percent(mm_player_streaming_t* streamer,
258 gdouble high_percent_byte,
259 gdouble high_percent_time)
261 gdouble confirmed_low = DEFAULT_BUFFER_LOW_PERCENT;
262 gdouble confirmed_high = DEFAULT_BUFFER_HIGH_PERCENT;
263 gdouble high_percent = 0.0;
265 streaming_buffer_t* buffer_handle = NULL;
266 gchar* factory_name = NULL;
269 MMPLAYER_RETURN_IF_FAIL(streamer);
270 MMPLAYER_RETURN_IF_FAIL(type < BUFFER_TYPE_MAX);
272 buffer_handle = &(streamer->buffer_handle[type]);
273 if (!(buffer_handle && buffer_handle->buffer)) {
274 LOGE("buffer_handle->buffer is NULL!");
278 factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer));
281 LOGE("Fail to get factory name!");
285 if (type == BUFFER_TYPE_MUXED)
286 high_percent = high_percent_byte;
288 high_percent = MAX(high_percent_time, high_percent_byte);
290 streaming_check_buffer_percent(low_percent, high_percent, &confirmed_low, &confirmed_high);
292 /* if use-buffering is disabled, this settings do not have any meaning. */
293 LOGD("target buffer elem : %s (%2.3f ~ %2.3f)",
294 GST_ELEMENT_NAME(buffer_handle->buffer), confirmed_low, confirmed_high);
296 if ((confirmed_low == DEFAULT_BUFFER_LOW_PERCENT) ||
297 (buffer_handle->buffer_low_percent != confirmed_low))
298 g_object_set(G_OBJECT(buffer_handle->buffer), "low-percent", (gint)confirmed_low, NULL);
300 if ((confirmed_high == DEFAULT_BUFFER_HIGH_PERCENT) ||
301 (buffer_handle->buffer_high_percent != confirmed_high))
302 g_object_set(G_OBJECT(buffer_handle->buffer), "high-percent", (gint)confirmed_high, NULL);
304 buffer_handle->buffer_low_percent = confirmed_low;
305 buffer_handle->buffer_high_percent = confirmed_high;
312 streaming_set_queue2_queue_type(mm_player_streaming_t* streamer, MuxedBufferType type, gchar * file_path, guint64 content_size)
314 streaming_buffer_t* buffer_handle = NULL;
315 guint64 storage_available_size = 0; /* bytes */
316 guint64 buffer_size = 0; /* bytes */
317 gchar file_buffer_name[MM_MAX_URL_LEN] = {0};
318 struct statfs buf = {0};
319 gchar* factory_name = NULL;
322 MMPLAYER_RETURN_IF_FAIL(streamer);
323 MMPLAYER_RETURN_IF_FAIL(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer);
325 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_MUXED]);
327 if (!(buffer_handle && buffer_handle->buffer)) {
328 LOGE("buffer_handle->buffer is NULL!");
332 factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer));
335 LOGE("Fail to get factory name!");
339 LOGD("target buffer elem : %s", GST_ELEMENT_NAME(buffer_handle->buffer));
341 if (!g_strrstr(factory_name, "queue2")) {
342 LOGD("only queue2 can use file buffer. not decodebin2 or multiQ\n");
346 if (type == MUXED_BUFFER_TYPE_MEM_QUEUE) {
347 LOGD("use memory queue for buffering. streaming is played on push-based. \n"
348 "buffering position would not be updated.\n"
349 "buffered data would be flushed after played.\n"
350 "seeking and getting duration could be failed due to file format.");
354 LOGD("[Queue2] buffering type : %d. streaming is played on pull-based. \n", type);
355 if (type == MUXED_BUFFER_TYPE_FILE && file_path && strlen(file_path) > 0) {
356 if (statfs((const char *)file_path, &buf) < 0) {
357 LOGW("[Queue2] fail to get available storage capacity. set mem ring buffer instead of file buffer.\n");
358 buffer_size = (guint64)((streamer->ring_buffer_size > 0) ? (streamer->ring_buffer_size) : DEFAULT_RING_BUFFER_SIZE);
360 storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes
362 LOGD("[Queue2] the number of available blocks : %"G_GUINT64_FORMAT
363 ", the block size is %"G_GUINT64_FORMAT".\n",
364 (guint64)buf.f_bavail, (guint64)buf.f_bsize);
366 LOGD("[Queue2] calculated available storage size is %"
367 G_GUINT64_FORMAT" Bytes.\n", storage_available_size);
369 if (content_size <= 0 || content_size >= storage_available_size)
370 buffer_size = storage_available_size;
374 g_snprintf(file_buffer_name, MM_MAX_URL_LEN, "%sXXXXXX", file_path);
375 SECURE_LOGD("[Queue2] the buffering file name is %s.\n", file_buffer_name);
377 g_object_set(G_OBJECT(buffer_handle->buffer), "temp-template", file_buffer_name, NULL);
380 buffer_size = (guint64)((streamer->ring_buffer_size > 0) ? (streamer->ring_buffer_size) : DEFAULT_RING_BUFFER_SIZE);
383 LOGW("[Queue2] set ring buffer size: %"G_GUINT64_FORMAT, buffer_size);
384 g_object_set(G_OBJECT(buffer_handle->buffer), "ring-buffer-max-size", buffer_size, NULL);
391 streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gint buffering_time)
393 streaming_buffer_t* buffer_handle = NULL;
397 MMPLAYER_RETURN_IF_FAIL(streamer);
398 MMPLAYER_RETURN_IF_FAIL(buffering_bytes > 0);
399 MMPLAYER_RETURN_IF_FAIL(type < BUFFER_TYPE_MAX);
401 buffer_handle = &(streamer->buffer_handle[type]);
403 if (buffer_handle && buffer_handle->buffer) {
404 if (g_strrstr(GST_ELEMENT_NAME(buffer_handle->buffer), "multiqueue")) {
405 if (buffering_time <= 0)
406 buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
408 g_object_set(G_OBJECT(buffer_handle->buffer),
409 "max-size-bytes", GET_MAX_BUFFER_BYTES(streamer), /* mq size is fixed, control it with high/low percent value*/
410 "max-size-time", (guint64)(buffering_time * GST_MSECOND),
411 "max-size-buffers", 0, NULL); /* disable */
413 buffer_handle->buffering_time = buffering_time;
414 buffer_handle->buffering_bytes = GET_MAX_BUFFER_BYTES(streamer);
416 LOGD("max-size-time : %d ms", buffering_time);
419 if (buffer_handle->is_live)
420 g_object_set(G_OBJECT(buffer_handle->buffer),
421 "max-size-bytes", buffering_bytes,
422 "max-size-time", (guint64)(buffering_time*GST_MSECOND),
423 "max-size-buffers", 0,
424 "use-rate-estimate", TRUE, NULL);
426 g_object_set(G_OBJECT(buffer_handle->buffer),
427 "max-size-bytes", buffering_bytes,
428 "max-size-time", (guint64)0,
429 "max-size-buffers", 0,
430 "use-rate-estimate", FALSE, NULL);
432 buffer_handle->buffering_bytes = buffering_bytes;
433 buffer_handle->buffering_time = buffering_time;
435 LOGD("max-size-bytes : %d", buffering_bytes);
443 void __mm_player_streaming_set_queue2(mm_player_streaming_t* streamer,
445 gboolean use_buffering,
446 guint buffering_bytes,
449 gdouble high_percent,
450 MuxedBufferType type,
452 guint64 content_size)
455 MMPLAYER_RETURN_IF_FAIL(streamer);
458 LOGD("USE-BUFFERING : %s", (use_buffering) ? "OOO" : "XXX");
460 streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer = buffer;
463 streamer->streaming_buffer_type = BUFFER_TYPE_MUXED;
465 if (content_size > 0) {
466 if (streamer->buffering_req.prebuffer_time > 0)
467 streamer->buffering_req.is_pre_buffering = TRUE;
469 streamer->buffering_req.prebuffer_time = buffering_time;
471 LOGD("live streaming without mq");
473 streamer->buffer_handle[BUFFER_TYPE_MUXED].is_live = TRUE;
474 streamer->buffering_req.prebuffer_time = buffering_time = DEFAULT_BUFFERING_TIME;
478 g_object_set(G_OBJECT(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), "use-buffering", use_buffering, NULL);
481 /* initial setting */
482 streaming_set_buffer_size(streamer, BUFFER_TYPE_MUXED, buffering_bytes, buffering_time);
483 streaming_set_buffer_percent(streamer, BUFFER_TYPE_MUXED, low_percent, high_percent, 0);
484 if (type < MUXED_BUFFER_TYPE_MAX)
485 streaming_set_queue2_queue_type(streamer, type, file_path, content_size);
491 void __mm_player_streaming_sync_property(mm_player_streaming_t* streamer, GstElement* decodebin)
493 streaming_buffer_t* buffer_handle = NULL;
497 MMPLAYER_RETURN_IF_FAIL(streamer && decodebin);
499 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
501 if ((streamer->need_sync) && (streamer->streaming_buffer_type == BUFFER_TYPE_DEMUXED)) {
502 g_object_set(G_OBJECT(decodebin),
503 "max-size-bytes", buffer_handle->buffering_bytes,
504 "max-size-time", (guint64)(buffer_handle->buffering_time * GST_MSECOND),
505 "low-percent", (gint)buffer_handle->buffer_low_percent,
506 "high-percent", (gint)buffer_handle->buffer_high_percent, NULL);
509 streamer->need_sync = FALSE;
512 void __mm_player_streaming_set_multiqueue(mm_player_streaming_t* streamer,
516 gdouble high_percent)
518 streaming_buffer_t* buffer_handle = NULL;
521 MMPLAYER_RETURN_IF_FAIL(streamer && buffer);
523 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
525 buffer_handle->buffer = buffer;
527 streamer->streaming_buffer_type = BUFFER_TYPE_DEMUXED;
528 g_object_set(G_OBJECT(buffer_handle->buffer), "use-buffering", TRUE, NULL);
531 LOGD("pre_buffering: %d ms, during playing: %d ms\n", streamer->buffering_req.prebuffer_time, buffering_time);
533 if (streamer->buffering_req.prebuffer_time > 0)
534 streamer->buffering_req.is_pre_buffering = TRUE;
536 streamer->buffering_req.prebuffer_time = GET_DEFAULT_PLAYING_TIME(streamer);
538 high_percent = (gdouble)(streamer->buffering_req.prebuffer_time * 100) / GET_MAX_BUFFER_TIME(streamer);
539 LOGD("high_percent %2.3f %%\n", high_percent);
541 /* initial setting */
542 streaming_set_buffer_size(streamer, BUFFER_TYPE_DEMUXED, GET_MAX_BUFFER_BYTES(streamer), GET_MAX_BUFFER_TIME(streamer));
543 streaming_set_buffer_percent(streamer, BUFFER_TYPE_DEMUXED, low_percent, 0, high_percent);
545 streamer->need_sync = TRUE;
552 streaming_get_current_bitrate_info(mm_player_streaming_t* streamer,
553 GstMessage *buffering_msg,
554 streaming_content_info_t content_info,
555 streaming_bitrate_info_t* bitrate_info)
558 GstQuery *query = NULL;
559 GstBufferingMode mode = GST_BUFFERING_STREAM;
562 gint64 buffering_left = -1;
564 guint buffer_criteria = 0;
565 guint estimated_content_bitrate = 0;
567 gint buffer_buffering_time = DEFAULT_BUFFERING_TIME;
571 MMPLAYER_RETURN_IF_FAIL(streamer);
572 MMPLAYER_RETURN_IF_FAIL(bitrate_info);
574 if ((buffering_msg == NULL) ||
575 ((streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer != NULL) &&
576 (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer != NULL) &&
577 (buffering_msg->src == (GstObject *)streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer))) {
578 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
580 if (gst_element_query((streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), query))
581 gst_query_parse_buffering_stats(query, &mode, &in_rate, &out_rate, &buffering_left);
582 gst_query_unref(query);
584 gst_message_parse_buffering_stats(buffering_msg, &mode, &in_rate, &out_rate, &buffering_left);
587 LOGD("Streaming Info : in %d, out %d, left %"G_GINT64_FORMAT, in_rate, out_rate, buffering_left);
589 if ((content_info.content_size > 0) && (content_info.duration > 0) && ((content_info.duration/GST_SECOND) > 0))
590 estimated_content_bitrate = GET_BIT_FROM_BYTE((guint)(content_info.content_size / (content_info.duration/GST_SECOND)));
592 if (streamer->buffer_max_bitrate > 0) {
593 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, streamer->buffer_avg_bitrate);
594 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, estimated_content_bitrate);
596 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate);
598 if (streamer->buffer_avg_bitrate > estimated_content_bitrate)
599 out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate);
600 else if (estimated_content_bitrate != 0)
601 out_rate = GET_BYTE_FROM_BIT(estimated_content_bitrate);
603 out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate/3);
605 LOGD("(max)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate);
606 } else if (streamer->buffer_avg_bitrate > 0) {
607 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3);
608 out_rate = GET_BYTE_FROM_BIT(MAX(streamer->buffer_avg_bitrate, estimated_content_bitrate));
610 LOGD("(avg)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate);
612 LOGW("There is no content bitrate information\n");
615 if ((in_rate > 0) && (out_rate > 0))
616 buffer_buffering_time = (gint)(out_rate / in_rate)*1000;
617 else if ((in_rate <= 0) && (out_rate > 0))
618 buffer_buffering_time = MAX_BUFFERING_TIME;
620 buffer_buffering_time = DEFAULT_BUFFERING_TIME;
622 (*bitrate_info).byte_in_rate = in_rate;
623 (*bitrate_info).byte_out_rate = out_rate;
624 (*bitrate_info).time_rate = buffer_buffering_time;
625 (*bitrate_info).buffer_criteria = buffer_criteria;
629 streaming_handle_fixed_buffering_mode(mm_player_streaming_t* streamer,
631 gint fixed_buffering_time,
632 streaming_buffer_info_t* buffer_info)
634 streaming_buffer_t* buffer_handle = NULL;
636 guint buffering_bytes = 0;
637 gint buffering_time = 0;
638 gdouble per_byte = 0.0;
639 gdouble per_time = 0.0;
641 MMPLAYER_RETURN_IF_FAIL(streamer);
642 MMPLAYER_RETURN_IF_FAIL(buffer_info);
644 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
645 buffering_time = fixed_buffering_time;
647 LOGD("buffering time: %d ms, out rate: %d\n", buffering_time, byte_out_rate);
649 if ((buffering_time > 0) && (byte_out_rate > 0)) {
650 buffering_bytes = (guint)GET_NEW_BUFFERING_BYTE((gdouble)(byte_out_rate * buffering_time)/1000);
652 if (buffering_time <= 0)
653 buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
655 LOGW("content bitrate is not updated yet.\n");
656 buffering_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle);
659 GET_PERCENT(buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time);
660 GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte);
662 LOGD("bytes %d, time %d, per_byte %f, per_time %f\n", buffering_bytes, buffering_time, per_byte, per_time);
664 (*buffer_info).buffering_bytes = buffering_bytes;
665 (*buffer_info).buffering_time = buffering_time;
666 (*buffer_info).percent_byte = per_byte;
667 (*buffer_info).percent_time = per_time;
671 streaming_handle_adaptive_buffering_mode(mm_player_streaming_t* streamer,
672 streaming_content_info_t content_info,
673 streaming_bitrate_info_t bitrate_info,
674 streaming_buffer_info_t* buffer_info,
675 gint expected_play_time)
677 streaming_buffer_t* buffer_handle = NULL;
679 gint buffering_bytes = 0;
680 gint adj_buffering_bytes = 0;
681 gint buffer_buffering_time = 0;
682 gdouble per_byte = 0.0;
683 gdouble per_time = 0.0;
684 gdouble portion = 0.0;
685 gint default_buffering_time = 0;
687 MMPLAYER_RETURN_IF_FAIL(streamer);
688 MMPLAYER_RETURN_IF_FAIL(buffer_info);
690 LOGD("pos %"G_GINT64_FORMAT", dur %"G_GINT64_FORMAT", size %"G_GUINT64_FORMAT", in/out:%d/%d, buffer_criteria:%d, time_rate:%d, need:%d ms\n",
691 content_info.position, content_info.duration, content_info.content_size,
692 bitrate_info.byte_in_rate, bitrate_info.byte_out_rate,
693 bitrate_info.buffer_criteria, bitrate_info.time_rate, expected_play_time);
695 if ((content_info.duration <= 0) ||
696 (content_info.content_size <= 0)) {
697 LOGW("keep previous setting.\n");
701 if ((bitrate_info.byte_out_rate <= 0) || (bitrate_info.buffer_criteria == 0)) {
702 LOGW("keep previous setting.\n");
706 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
708 if (bitrate_info.byte_in_rate < bitrate_info.byte_out_rate) {
709 portion = (double)(expected_play_time * GST_MSECOND) / (double)content_info.duration;
710 buffering_bytes = GET_NEW_BUFFERING_BYTE(((double)content_info.content_size * portion) \
711 * (1 - (double)bitrate_info.byte_in_rate/(double)bitrate_info.byte_out_rate));
713 /* buffering_bytes will be set as streamer->default_val.buffering_time *
714 * receiving rate is bigger than avg content bitrate
715 * so there is no reason to buffering. if the buffering msg is posted
716 * in-rate or contents bitrate has wrong value. */
717 LOGW("don't need to do buffering.\n");
720 if (buffering_bytes > 0)
721 buffer_buffering_time = (gint)(buffering_bytes / bitrate_info.byte_out_rate)*1000;
723 if (content_info.position <= 0) {
724 /* if the buffer is filled under 50%, MSL use the original default buffering time.
725 if not, MSL use just 2 sec as a default buffering time. (to reduce initial buffering time) */
726 default_buffering_time = streamer->default_val.buffering_time - ((gdouble)streamer->buffering_percent/50)*1000;
728 default_buffering_time = streamer->default_val.buffering_time;
731 if (buffer_buffering_time < default_buffering_time) {
732 LOGD("adjusted time: %d -> %d ms\n", buffer_buffering_time, default_buffering_time);
733 LOGD("adjusted bytes : %d or %d or %d\n",
735 (gint)(bitrate_info.byte_out_rate * buffer_buffering_time/1000),
736 (gint)(bitrate_info.buffer_criteria * buffer_buffering_time/1000));
738 /* start monitoring the abmormal state */
739 if (content_info.position > 0)
740 streamer->default_val.buffering_monitor = TRUE;
742 buffer_buffering_time = default_buffering_time;
743 adj_buffering_bytes = GET_NEW_BUFFERING_BYTE(bitrate_info.byte_out_rate * (gint)ceil((gdouble)buffer_buffering_time/1000));
744 buffering_bytes = MAX(buffering_bytes, adj_buffering_bytes);
747 GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte);
748 GET_PERCENT(buffer_buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time);
750 LOGD("monitor %d, bytes %d, time %d, per_byte %f, per_time %f\n",
751 streamer->default_val.buffering_monitor,
752 buffering_bytes, buffer_buffering_time, per_byte, per_time);
754 (*buffer_info).buffering_bytes = buffering_bytes;
755 (*buffer_info).buffering_time = buffer_buffering_time;
756 (*buffer_info).percent_byte = per_byte;
757 (*buffer_info).percent_time = per_time;
762 streaming_update_buffer_setting(mm_player_streaming_t* streamer,
763 GstMessage *buffering_msg, /* can be null */
764 guint64 content_size,
768 streaming_buffer_t* buffer_handle = NULL;
769 MMPlayerBufferingMode buffering_mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
771 streaming_buffer_info_t buffer_info;
772 streaming_content_info_t content_info;
773 streaming_bitrate_info_t bitrate_info;
775 gdouble low_percent = 0.0;
779 MMPLAYER_RETURN_IF_FAIL(streamer);
781 memset(&buffer_info, 0x00, sizeof(streaming_buffer_info_t));
782 memset(&content_info, 0x00, sizeof(streaming_content_info_t));
783 memset(&bitrate_info, 0x00, sizeof(streaming_bitrate_info_t));
785 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
787 if (streamer->buffering_req.is_pre_buffering == TRUE)
788 buffering_mode = MM_PLAYER_BUFFERING_MODE_FIXED;
790 buffering_mode = streamer->buffering_req.mode;
792 buffer_info.buffering_bytes = buffer_handle->buffering_bytes;
793 buffer_info.buffering_time = buffer_handle->buffering_time;
794 buffer_info.percent_byte = buffer_handle->buffer_high_percent;
795 buffer_info.percent_time = buffer_handle->buffer_high_percent;
797 content_info.position = position;
798 content_info.duration = duration;
799 content_info.content_size = content_size;
801 streaming_get_current_bitrate_info(streamer, buffering_msg, content_info, &bitrate_info);
803 LOGD("buffering mode %d, new info in_r:%d, out_r:%d, cb:%d, bt:%d\n",
804 buffering_mode, bitrate_info.byte_in_rate, bitrate_info.byte_out_rate,
805 bitrate_info.buffer_criteria, bitrate_info.time_rate);
807 /* calculate buffer low/high percent */
808 low_percent = DEFAULT_BUFFER_LOW_PERCENT;
810 if (buffering_mode == MM_PLAYER_BUFFERING_MODE_FIXED) {
811 /********************
813 ********************/
814 gint buffering_time = 0;
816 if (streamer->buffering_req.is_pre_buffering == TRUE)
817 buffering_time = streamer->buffering_req.prebuffer_time;
819 buffering_time = streamer->buffering_req.rebuffer_time;
821 streaming_handle_fixed_buffering_mode(streamer, bitrate_info.byte_out_rate, buffering_time, &buffer_info);
823 /*********************************
824 * (2) adaptive mode (default) *
825 *********************************/
826 gint expected_play_time = DEFAULT_PLAYING_TIME;
828 if (streamer->buffering_req.rebuffer_time > 0)
829 expected_play_time = streamer->buffering_req.rebuffer_time;
830 else if ((position == 0) && (streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS))
831 expected_play_time = streamer->buffering_req.prebuffer_time;
833 if (expected_play_time <= 0)
834 expected_play_time = DEFAULT_PLAYING_TIME;
836 streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, expected_play_time);
838 if (IS_MUXED_BUFFERING_MODE(streamer)) // even if new byte size is smaller than the previous one, time need to be updated.
839 buffer_handle->buffering_time = buffer_info.buffering_time;
842 LOGD("adj buffer(%d) %d->%d bytes/%d->%d ms\n",
843 streamer->streaming_buffer_type,
844 GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_info.buffering_bytes,
845 GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_info.buffering_time);
847 /* queue2 : bytes, multiqueue : time */
848 if (((GET_CURRENT_BUFFERING_BYTE(buffer_handle) < buffer_info.buffering_bytes) && IS_MUXED_BUFFERING_MODE(streamer)) ||
849 ((GET_CURRENT_BUFFERING_TIME(buffer_handle) < buffer_info.buffering_time) && IS_DEMUXED_BUFFERING_MODE(streamer))) {
850 if (duration > 0 && position > 0) {
851 gint buffering_time_limit = (gint)(duration - position)/GST_MSECOND;
853 if (buffer_info.buffering_time > buffering_time_limit)
854 buffer_info.buffering_time = buffering_time_limit;
857 streaming_set_buffer_size(streamer, streamer->streaming_buffer_type, buffer_info.buffering_bytes, buffer_info.buffering_time);
860 streaming_set_buffer_percent(streamer, streamer->streaming_buffer_type, low_percent, buffer_info.percent_byte, buffer_info.percent_time);
862 LOGD("buffer setting: size %d, time %d, per %f\n",
863 GET_CURRENT_BUFFERING_BYTE(buffer_handle),
864 GET_CURRENT_BUFFERING_TIME(buffer_handle),
865 buffer_handle->buffer_high_percent);
867 streamer->need_sync = TRUE;
871 streaming_adjust_min_threshold(mm_player_streaming_t* streamer, gint64 position)
873 #define DEFAULT_TIME_PAD 1000 /* ms */
874 gint playing_time = 0;
878 MMPLAYER_RETURN_IF_FAIL(streamer);
880 playing_time = (gint)((position - streamer->default_val.prev_pos) / GST_MSECOND);
882 LOGD("buffering monitor = %s", (streamer->default_val.buffering_monitor) ? "ON" : "OFF");
883 LOGD("playing_time (%d ms) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT, playing_time, position, streamer->default_val.prev_pos);
884 LOGD("default time : %d, prev buffering t : %d",
885 streamer->default_val.buffering_time, streamer->buffer_handle[streamer->streaming_buffer_type].buffering_time);
887 if ((streamer->default_val.buffering_monitor) && (playing_time <= streamer->default_val.buffering_time)) {
889 time_gap = streamer->default_val.buffering_time - DEFAULT_BUFFERING_TIME;
891 time_gap = DEFAULT_TIME_PAD;
893 streamer->default_val.buffering_time += time_gap*2;
894 streamer->default_val.buffering_time = MIN(streamer->default_val.buffering_time, MAX_BUFFERING_TIME);
896 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
899 LOGD("new default min value %d \n", streamer->default_val.buffering_time);
901 streamer->default_val.buffering_monitor = FALSE;
902 streamer->default_val.prev_pos = position;
906 streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position)
908 gint buffer_percent = 0;
912 MMPLAYER_RETURN_IF_FAIL(streamer);
913 MMPLAYER_RETURN_IF_FAIL(buffering_msg);
915 /* update when buffering has started. */
916 if (!(streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
917 streamer->buffering_state = MM_PLAYER_BUFFERING_IN_PROGRESS;
918 streamer->buffering_percent = -1;
920 if (!streamer->buffering_req.is_pre_buffering) {
921 streamer->need_update = TRUE;
922 streaming_adjust_min_threshold(streamer, position);
926 /* update buffer percent */
927 gst_message_parse_buffering(buffering_msg, &buffer_percent);
929 /* LOGD("[%s] buffering per %d%% -> %d%%, state 0x%X", streamer->buffering_percent, buffer_percent, streamer->buffering_state); */
931 if (streamer->buffering_percent < buffer_percent) {
932 LOGD("[%s] buffering %d%%....",
933 GST_OBJECT_NAME(GST_MESSAGE_SRC(buffering_msg)), buffer_percent);
934 streamer->buffering_percent = buffer_percent;
937 if (streamer->buffering_percent == MAX_BUFFER_PERCENT) {
938 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
939 streamer->buffering_req.is_pre_buffering = FALSE;
940 } else if (streamer->buffering_state & MM_PLAYER_BUFFERING_COMPLETE) {
941 streamer->buffering_state = MM_PLAYER_BUFFERING_COMPLETE; /* have to keep state to ignore remained msg till get 100% msg */
942 streamer->buffering_req.is_pre_buffering = FALSE;
943 streamer->buffering_percent = MAX_BUFFER_PERCENT;
944 LOGD("updated to the buffering 100%%.... (by force)");
948 void __mm_player_streaming_buffering(mm_player_streaming_t* streamer,
949 GstMessage *buffering_msg,
950 guint64 content_size,
956 MMPLAYER_RETURN_IF_FAIL(streamer);
957 MMPLAYER_RETURN_IF_FAIL(buffering_msg);
958 MMPLAYER_RETURN_IF_FAIL(GST_IS_MESSAGE(buffering_msg));
959 MMPLAYER_RETURN_IF_FAIL((GST_MESSAGE_TYPE(buffering_msg) == GST_MESSAGE_BUFFERING));
961 if (position > (gint64)(streamer->buffering_req.prebuffer_time * GST_MSECOND))
962 streamer->buffering_req.is_pre_buffering = FALSE;
964 streaming_update_buffering_status(streamer, buffering_msg, position);
966 if (!streamer->need_update)
969 streamer->need_update = FALSE;
970 streaming_update_buffer_setting(streamer, buffering_msg, content_size, position, duration);