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;
131 streamer->is_pd_mode = FALSE;
133 streamer->buffering_percent = -1;
134 streamer->ring_buffer_size = DEFAULT_RING_BUFFER_SIZE;
140 void __mm_player_streaming_deinitialize(mm_player_streaming_t* streamer)
143 MMPLAYER_RETURN_IF_FAIL(streamer);
145 streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue
147 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), FALSE);
148 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), FALSE);
150 streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
151 streamer->buffering_req.is_pre_buffering = FALSE;
152 streamer->buffering_req.prebuffer_time = 0;
153 streamer->buffering_req.rebuffer_time = 0;
155 streamer->default_val.buffering_monitor = FALSE;
156 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
158 streamer->buffer_avg_bitrate = 0;
159 streamer->buffer_max_bitrate = 0;
160 streamer->need_update = FALSE;
161 streamer->need_sync = FALSE;
163 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
164 streamer->is_adaptive_streaming = FALSE;
165 streamer->is_pd_mode = FALSE;
167 streamer->buffering_percent = -1;
168 streamer->ring_buffer_size = DEFAULT_RING_BUFFER_SIZE;
174 void __mm_player_streaming_destroy(mm_player_streaming_t* streamer)
185 void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate)
189 MMPLAYER_RETURN_IF_FAIL(streamer);
191 /* Note : Update buffering criterion bytes
192 * 1. maximum bitrate is considered first.
193 * 2. average bitrage * 3 is next.
194 * 3. if there are no updated bitrate, use default buffering limit.
196 if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate) {
197 LOGD("set maximum bitrate(%dbps).\n", max_bitrate);
198 streamer->buffer_max_bitrate = max_bitrate;
199 if (streamer->buffering_req.is_pre_buffering == FALSE) {
200 streamer->need_update = TRUE;
202 LOGD("pre-buffering...\n");
204 if (IS_MUXED_BUFFERING_MODE(streamer))
205 streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
209 if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate) {
210 LOGD("set averate bitrate(%dbps).\n", avg_bitrate);
211 streamer->buffer_avg_bitrate = avg_bitrate;
213 if (streamer->buffering_req.is_pre_buffering == FALSE) {
214 streamer->need_update = TRUE;
216 LOGD("pre-buffering...\n");
218 if (IS_MUXED_BUFFERING_MODE(streamer))
219 streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
228 streaming_check_buffer_percent(gdouble in_low, gdouble in_high, gdouble *out_low, gdouble *out_high)
230 gdouble buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
231 gdouble buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
235 MMPLAYER_RETURN_IF_FAIL(out_low && out_high);
237 if (in_low <= MIN_BUFFER_PERCENT || in_low >= MAX_BUFFER_PERCENT)
238 LOGW("buffer low percent is out of range. use defaut value.");
240 buffer_low_percent = in_low;
242 if (in_high <= MIN_BUFFER_PERCENT || in_high >= MAX_BUFFER_PERCENT)
243 LOGW("buffer high percent is out of range. use defaut value.");
245 buffer_high_percent = in_high;
247 if (buffer_high_percent <= buffer_low_percent)
248 buffer_high_percent = buffer_low_percent + 1.0;
250 LOGD("set buffer percent to %2.3f ~ %2.3f.", buffer_low_percent, buffer_high_percent);
252 *out_low = buffer_low_percent;
253 *out_high = buffer_high_percent;
257 streaming_set_buffer_percent(mm_player_streaming_t* streamer,
260 gdouble high_percent_byte,
261 gdouble high_percent_time)
263 gdouble confirmed_low = DEFAULT_BUFFER_LOW_PERCENT;
264 gdouble confirmed_high = DEFAULT_BUFFER_HIGH_PERCENT;
265 gdouble high_percent = 0.0;
267 streaming_buffer_t* buffer_handle = NULL;
268 gchar* factory_name = NULL;
271 MMPLAYER_RETURN_IF_FAIL(streamer);
272 MMPLAYER_RETURN_IF_FAIL(type < BUFFER_TYPE_MAX);
274 buffer_handle = &(streamer->buffer_handle[type]);
275 if (!(buffer_handle && buffer_handle->buffer)) {
276 LOGE("buffer_handle->buffer is NULL!");
280 factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer));
283 LOGE("Fail to get factory name!");
287 if (type == BUFFER_TYPE_MUXED)
288 high_percent = high_percent_byte;
290 high_percent = MAX(high_percent_time, high_percent_byte);
292 streaming_check_buffer_percent(low_percent, high_percent, &confirmed_low, &confirmed_high);
294 /* if use-buffering is disabled, this settings do not have any meaning. */
295 LOGD("target buffer elem : %s (%2.3f ~ %2.3f)",
296 GST_ELEMENT_NAME(buffer_handle->buffer), confirmed_low, confirmed_high);
298 if ((confirmed_low == DEFAULT_BUFFER_LOW_PERCENT) ||
299 (buffer_handle->buffer_low_percent != confirmed_low))
300 g_object_set(G_OBJECT(buffer_handle->buffer), "low-percent", (gint)confirmed_low, NULL);
302 if ((confirmed_high == DEFAULT_BUFFER_HIGH_PERCENT) ||
303 (buffer_handle->buffer_high_percent != confirmed_high))
304 g_object_set(G_OBJECT(buffer_handle->buffer), "high-percent", (gint)confirmed_high, NULL);
306 buffer_handle->buffer_low_percent = confirmed_low;
307 buffer_handle->buffer_high_percent = confirmed_high;
314 streaming_set_queue2_queue_type(mm_player_streaming_t* streamer, MuxedBufferType type, gchar * file_path, guint64 content_size)
316 streaming_buffer_t* buffer_handle = NULL;
317 guint64 storage_available_size = 0; /* bytes */
318 guint64 buffer_size = 0; /* bytes */
319 gchar file_buffer_name[MM_MAX_URL_LEN] = {0};
320 struct statfs buf = {0};
321 gchar* factory_name = NULL;
324 MMPLAYER_RETURN_IF_FAIL(streamer);
325 MMPLAYER_RETURN_IF_FAIL(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer);
327 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_MUXED]);
329 if (!(buffer_handle && buffer_handle->buffer)) {
330 LOGE("buffer_handle->buffer is NULL!");
334 factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer));
337 LOGE("Fail to get factory name!");
341 LOGD("target buffer elem : %s", GST_ELEMENT_NAME(buffer_handle->buffer));
343 if (!g_strrstr(factory_name, "queue2")) {
344 LOGD("only queue2 can use file buffer. not decodebin2 or multiQ\n");
348 if (type == MUXED_BUFFER_TYPE_MEM_QUEUE) {
349 LOGD("use memory queue for buffering. streaming is played on push-based. \n"
350 "buffering position would not be updated.\n"
351 "buffered data would be flushed after played.\n"
352 "seeking and getting duration could be failed due to file format.");
356 LOGD("[Queue2] buffering type : %d. streaming is played on pull-based. \n", type);
357 if (type == MUXED_BUFFER_TYPE_FILE && file_path && strlen(file_path) > 0) {
358 if (statfs((const char *)file_path, &buf) < 0) {
359 LOGW("[Queue2] fail to get available storage capacity. set mem ring buffer instead of file buffer.\n");
360 buffer_size = (guint64)((streamer->ring_buffer_size > 0) ? (streamer->ring_buffer_size) : DEFAULT_RING_BUFFER_SIZE);
362 storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes
364 LOGD("[Queue2] the number of available blocks : %"G_GUINT64_FORMAT
365 ", the block size is %"G_GUINT64_FORMAT".\n",
366 (guint64)buf.f_bavail, (guint64)buf.f_bsize);
368 LOGD("[Queue2] calculated available storage size is %"
369 G_GUINT64_FORMAT" Bytes.\n", storage_available_size);
371 if (content_size <= 0 || content_size >= storage_available_size)
372 buffer_size = storage_available_size;
376 g_snprintf(file_buffer_name, MM_MAX_URL_LEN, "%sXXXXXX", file_path);
377 SECURE_LOGD("[Queue2] the buffering file name is %s.\n", file_buffer_name);
379 g_object_set(G_OBJECT(buffer_handle->buffer), "temp-template", file_buffer_name, NULL);
382 buffer_size = (guint64)((streamer->ring_buffer_size > 0) ? (streamer->ring_buffer_size) : DEFAULT_RING_BUFFER_SIZE);
385 LOGW("[Queue2] set ring buffer size: %"G_GUINT64_FORMAT, buffer_size);
386 g_object_set(G_OBJECT(buffer_handle->buffer), "ring-buffer-max-size", buffer_size, NULL);
393 streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gint buffering_time)
395 streaming_buffer_t* buffer_handle = NULL;
399 MMPLAYER_RETURN_IF_FAIL(streamer);
400 MMPLAYER_RETURN_IF_FAIL(buffering_bytes > 0);
401 MMPLAYER_RETURN_IF_FAIL(type < BUFFER_TYPE_MAX);
403 buffer_handle = &(streamer->buffer_handle[type]);
405 if (buffer_handle && buffer_handle->buffer) {
406 if (g_strrstr(GST_ELEMENT_NAME(buffer_handle->buffer), "multiqueue")) {
407 if (buffering_time <= 0)
408 buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
410 g_object_set(G_OBJECT(buffer_handle->buffer),
411 "max-size-bytes", GET_MAX_BUFFER_BYTES(streamer), /* mq size is fixed, control it with high/low percent value*/
412 "max-size-time", (guint64)(buffering_time * GST_MSECOND),
413 "max-size-buffers", 0, NULL); /* disable */
415 buffer_handle->buffering_time = buffering_time;
416 buffer_handle->buffering_bytes = GET_MAX_BUFFER_BYTES(streamer);
418 LOGD("max-size-time : %d ms", buffering_time);
421 if (buffer_handle->is_live)
422 g_object_set(G_OBJECT(buffer_handle->buffer),
423 "max-size-bytes", buffering_bytes,
424 "max-size-time", (guint64)(buffering_time*GST_MSECOND),
425 "max-size-buffers", 0,
426 "use-rate-estimate", TRUE, NULL);
428 g_object_set(G_OBJECT(buffer_handle->buffer),
429 "max-size-bytes", buffering_bytes,
430 "max-size-time", (guint64)0,
431 "max-size-buffers", 0,
432 "use-rate-estimate", FALSE, NULL);
434 buffer_handle->buffering_bytes = buffering_bytes;
435 buffer_handle->buffering_time = buffering_time;
437 LOGD("max-size-bytes : %d", buffering_bytes);
445 void __mm_player_streaming_set_queue2(mm_player_streaming_t* streamer,
447 gboolean use_buffering,
448 guint buffering_bytes,
451 gdouble high_percent,
452 MuxedBufferType type,
454 guint64 content_size)
457 MMPLAYER_RETURN_IF_FAIL(streamer);
460 LOGD("USE-BUFFERING : %s", (use_buffering) ? "OOO" : "XXX");
462 streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer = buffer;
465 streamer->streaming_buffer_type = BUFFER_TYPE_MUXED;
467 if (content_size > 0 || streamer->is_pd_mode) {
468 if (streamer->buffering_req.prebuffer_time > 0)
469 streamer->buffering_req.is_pre_buffering = TRUE;
471 streamer->buffering_req.prebuffer_time = buffering_time;
473 LOGD("live streaming without mq");
475 streamer->buffer_handle[BUFFER_TYPE_MUXED].is_live = TRUE;
476 streamer->buffering_req.prebuffer_time = buffering_time = DEFAULT_BUFFERING_TIME;
480 g_object_set(G_OBJECT(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), "use-buffering", use_buffering, NULL);
483 /* initial setting */
484 streaming_set_buffer_size(streamer, BUFFER_TYPE_MUXED, buffering_bytes, buffering_time);
485 streaming_set_buffer_percent(streamer, BUFFER_TYPE_MUXED, low_percent, high_percent, 0);
486 if (type < MUXED_BUFFER_TYPE_MAX)
487 streaming_set_queue2_queue_type(streamer, type, file_path, content_size);
493 void __mm_player_streaming_sync_property(mm_player_streaming_t* streamer, GstElement* decodebin)
495 streaming_buffer_t* buffer_handle = NULL;
499 MMPLAYER_RETURN_IF_FAIL(streamer && decodebin);
501 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
503 if ((streamer->need_sync) && (streamer->streaming_buffer_type == BUFFER_TYPE_DEMUXED)) {
504 g_object_set(G_OBJECT(decodebin),
505 "max-size-bytes", buffer_handle->buffering_bytes,
506 "max-size-time", (guint64)(buffer_handle->buffering_time * GST_MSECOND),
507 "low-percent", (gint)buffer_handle->buffer_low_percent,
508 "high-percent", (gint)buffer_handle->buffer_high_percent, NULL);
511 streamer->need_sync = FALSE;
514 void __mm_player_streaming_set_multiqueue(mm_player_streaming_t* streamer,
518 gdouble high_percent)
520 streaming_buffer_t* buffer_handle = NULL;
523 MMPLAYER_RETURN_IF_FAIL(streamer && buffer);
525 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
527 buffer_handle->buffer = buffer;
529 streamer->streaming_buffer_type = BUFFER_TYPE_DEMUXED;
530 g_object_set(G_OBJECT(buffer_handle->buffer), "use-buffering", TRUE, NULL);
533 LOGD("pre_buffering: %d ms, during playing: %d ms\n", streamer->buffering_req.prebuffer_time, buffering_time);
535 if (streamer->buffering_req.prebuffer_time > 0)
536 streamer->buffering_req.is_pre_buffering = TRUE;
538 streamer->buffering_req.prebuffer_time = GET_DEFAULT_PLAYING_TIME(streamer);
540 high_percent = (gdouble)(streamer->buffering_req.prebuffer_time * 100) / GET_MAX_BUFFER_TIME(streamer);
541 LOGD("high_percent %2.3f %%\n", high_percent);
543 /* initial setting */
544 streaming_set_buffer_size(streamer, BUFFER_TYPE_DEMUXED, GET_MAX_BUFFER_BYTES(streamer), GET_MAX_BUFFER_TIME(streamer));
545 streaming_set_buffer_percent(streamer, BUFFER_TYPE_DEMUXED, low_percent, 0, high_percent);
547 streamer->need_sync = TRUE;
554 streaming_get_current_bitrate_info(mm_player_streaming_t* streamer,
555 GstMessage *buffering_msg,
556 streaming_content_info_t content_info,
557 streaming_bitrate_info_t* bitrate_info)
560 GstQuery *query = NULL;
561 GstBufferingMode mode = GST_BUFFERING_STREAM;
564 gint64 buffering_left = -1;
566 guint buffer_criteria = 0;
567 guint estimated_content_bitrate = 0;
569 gint buffer_buffering_time = DEFAULT_BUFFERING_TIME;
573 MMPLAYER_RETURN_IF_FAIL(streamer);
574 MMPLAYER_RETURN_IF_FAIL(bitrate_info);
576 if ((buffering_msg == NULL) ||
577 ((streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer != NULL) &&
578 (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer != NULL) &&
579 (buffering_msg->src == (GstObject *)streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer))) {
580 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
582 if (gst_element_query((streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), query))
583 gst_query_parse_buffering_stats(query, &mode, &in_rate, &out_rate, &buffering_left);
584 gst_query_unref(query);
586 gst_message_parse_buffering_stats(buffering_msg, &mode, &in_rate, &out_rate, &buffering_left);
589 LOGD("Streaming Info : in %d, out %d, left %"G_GINT64_FORMAT, in_rate, out_rate, buffering_left);
591 if ((content_info.content_size > 0) && (content_info.duration > 0) && ((content_info.duration/GST_SECOND) > 0))
592 estimated_content_bitrate = GET_BIT_FROM_BYTE((guint)(content_info.content_size / (content_info.duration/GST_SECOND)));
594 if (streamer->buffer_max_bitrate > 0) {
595 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, streamer->buffer_avg_bitrate);
596 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, estimated_content_bitrate);
598 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate);
600 if (streamer->buffer_avg_bitrate > estimated_content_bitrate)
601 out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate);
602 else if (estimated_content_bitrate != 0)
603 out_rate = GET_BYTE_FROM_BIT(estimated_content_bitrate);
605 out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate/3);
607 LOGD("(max)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate);
608 } else if (streamer->buffer_avg_bitrate > 0) {
609 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3);
610 out_rate = GET_BYTE_FROM_BIT(MAX(streamer->buffer_avg_bitrate, estimated_content_bitrate));
612 LOGD("(avg)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate);
614 LOGW("There is no content bitrate information\n");
617 if ((in_rate > 0) && (out_rate > 0))
618 buffer_buffering_time = (gint)(out_rate / in_rate)*1000;
619 else if ((in_rate <= 0) && (out_rate > 0))
620 buffer_buffering_time = MAX_BUFFERING_TIME;
622 buffer_buffering_time = DEFAULT_BUFFERING_TIME;
624 (*bitrate_info).byte_in_rate = in_rate;
625 (*bitrate_info).byte_out_rate = out_rate;
626 (*bitrate_info).time_rate = buffer_buffering_time;
627 (*bitrate_info).buffer_criteria = buffer_criteria;
631 streaming_handle_fixed_buffering_mode(mm_player_streaming_t* streamer,
633 gint fixed_buffering_time,
634 streaming_buffer_info_t* buffer_info)
636 streaming_buffer_t* buffer_handle = NULL;
638 guint buffering_bytes = 0;
639 gint buffering_time = 0;
640 gdouble per_byte = 0.0;
641 gdouble per_time = 0.0;
643 MMPLAYER_RETURN_IF_FAIL(streamer);
644 MMPLAYER_RETURN_IF_FAIL(buffer_info);
646 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
647 buffering_time = fixed_buffering_time;
649 LOGD("buffering time: %d ms, out rate: %d\n", buffering_time, byte_out_rate);
651 if ((buffering_time > 0) && (byte_out_rate > 0)) {
652 buffering_bytes = (guint)GET_NEW_BUFFERING_BYTE((gdouble)(byte_out_rate * buffering_time)/1000);
654 if (buffering_time <= 0)
655 buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
657 LOGW("content bitrate is not updated yet.\n");
658 buffering_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle);
661 GET_PERCENT(buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time);
662 GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte);
664 LOGD("bytes %d, time %d, per_byte %f, per_time %f\n", buffering_bytes, buffering_time, per_byte, per_time);
666 (*buffer_info).buffering_bytes = buffering_bytes;
667 (*buffer_info).buffering_time = buffering_time;
668 (*buffer_info).percent_byte = per_byte;
669 (*buffer_info).percent_time = per_time;
673 streaming_handle_adaptive_buffering_mode(mm_player_streaming_t* streamer,
674 streaming_content_info_t content_info,
675 streaming_bitrate_info_t bitrate_info,
676 streaming_buffer_info_t* buffer_info,
677 gint expected_play_time)
679 streaming_buffer_t* buffer_handle = NULL;
681 gint buffering_bytes = 0;
682 gint adj_buffering_bytes = 0;
683 gint buffer_buffering_time = 0;
684 gdouble per_byte = 0.0;
685 gdouble per_time = 0.0;
686 gdouble portion = 0.0;
687 gint default_buffering_time = 0;
689 MMPLAYER_RETURN_IF_FAIL(streamer);
690 MMPLAYER_RETURN_IF_FAIL(buffer_info);
692 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",
693 content_info.position, content_info.duration, content_info.content_size,
694 bitrate_info.byte_in_rate, bitrate_info.byte_out_rate,
695 bitrate_info.buffer_criteria, bitrate_info.time_rate, expected_play_time);
697 if ((content_info.duration <= 0) ||
698 (content_info.content_size <= 0)) {
699 LOGW("keep previous setting.\n");
703 if ((bitrate_info.byte_out_rate <= 0) || (bitrate_info.buffer_criteria == 0)) {
704 LOGW("keep previous setting.\n");
708 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
710 if (bitrate_info.byte_in_rate < bitrate_info.byte_out_rate) {
711 portion = (double)(expected_play_time * GST_MSECOND) / (double)content_info.duration;
712 buffering_bytes = GET_NEW_BUFFERING_BYTE(((double)content_info.content_size * portion) \
713 * (1 - (double)bitrate_info.byte_in_rate/(double)bitrate_info.byte_out_rate));
715 /* buffering_bytes will be set as streamer->default_val.buffering_time *
716 * receiving rate is bigger than avg content bitrate
717 * so there is no reason to buffering. if the buffering msg is posted
718 * in-rate or contents bitrate has wrong value. */
719 LOGW("don't need to do buffering.\n");
722 if (buffering_bytes > 0)
723 buffer_buffering_time = (gint)(buffering_bytes / bitrate_info.byte_out_rate)*1000;
725 if (content_info.position <= 0) {
726 /* if the buffer is filled under 50%, MSL use the original default buffering time.
727 if not, MSL use just 2 sec as a default buffering time. (to reduce initial buffering time) */
728 default_buffering_time = streamer->default_val.buffering_time - ((gdouble)streamer->buffering_percent/50)*1000;
730 default_buffering_time = streamer->default_val.buffering_time;
733 if (buffer_buffering_time < default_buffering_time) {
734 LOGD("adjusted time: %d -> %d ms\n", buffer_buffering_time, default_buffering_time);
735 LOGD("adjusted bytes : %d or %d or %d\n",
737 (gint)(bitrate_info.byte_out_rate * buffer_buffering_time/1000),
738 (gint)(bitrate_info.buffer_criteria * buffer_buffering_time/1000));
740 /* start monitoring the abmormal state */
741 if (content_info.position > 0)
742 streamer->default_val.buffering_monitor = TRUE;
744 buffer_buffering_time = default_buffering_time;
745 adj_buffering_bytes = GET_NEW_BUFFERING_BYTE(bitrate_info.byte_out_rate * (gint)ceil((gdouble)buffer_buffering_time/1000));
746 buffering_bytes = MAX(buffering_bytes, adj_buffering_bytes);
749 GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte);
750 GET_PERCENT(buffer_buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time);
752 LOGD("monitor %d, bytes %d, time %d, per_byte %f, per_time %f\n",
753 streamer->default_val.buffering_monitor,
754 buffering_bytes, buffer_buffering_time, per_byte, per_time);
756 (*buffer_info).buffering_bytes = buffering_bytes;
757 (*buffer_info).buffering_time = buffer_buffering_time;
758 (*buffer_info).percent_byte = per_byte;
759 (*buffer_info).percent_time = per_time;
764 streaming_update_buffer_setting(mm_player_streaming_t* streamer,
765 GstMessage *buffering_msg, /* can be null */
766 guint64 content_size,
770 streaming_buffer_t* buffer_handle = NULL;
771 MMPlayerBufferingMode buffering_mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
773 streaming_buffer_info_t buffer_info;
774 streaming_content_info_t content_info;
775 streaming_bitrate_info_t bitrate_info;
777 gdouble low_percent = 0.0;
781 MMPLAYER_RETURN_IF_FAIL(streamer);
783 memset(&buffer_info, 0x00, sizeof(streaming_buffer_info_t));
784 memset(&content_info, 0x00, sizeof(streaming_content_info_t));
785 memset(&bitrate_info, 0x00, sizeof(streaming_bitrate_info_t));
787 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
789 if (streamer->buffering_req.is_pre_buffering == TRUE)
790 buffering_mode = MM_PLAYER_BUFFERING_MODE_FIXED;
792 buffering_mode = streamer->buffering_req.mode;
794 buffer_info.buffering_bytes = buffer_handle->buffering_bytes;
795 buffer_info.buffering_time = buffer_handle->buffering_time;
796 buffer_info.percent_byte = buffer_handle->buffer_high_percent;
797 buffer_info.percent_time = buffer_handle->buffer_high_percent;
799 content_info.position = position;
800 content_info.duration = duration;
801 content_info.content_size = content_size;
803 streaming_get_current_bitrate_info(streamer, buffering_msg, content_info, &bitrate_info);
805 LOGD("buffering mode %d, new info in_r:%d, out_r:%d, cb:%d, bt:%d\n",
806 buffering_mode, bitrate_info.byte_in_rate, bitrate_info.byte_out_rate,
807 bitrate_info.buffer_criteria, bitrate_info.time_rate);
809 /* calculate buffer low/high percent */
810 low_percent = DEFAULT_BUFFER_LOW_PERCENT;
812 if (buffering_mode == MM_PLAYER_BUFFERING_MODE_FIXED) {
813 /********************
815 ********************/
816 gint buffering_time = 0;
818 if (streamer->buffering_req.is_pre_buffering == TRUE)
819 buffering_time = streamer->buffering_req.prebuffer_time;
821 buffering_time = streamer->buffering_req.rebuffer_time;
823 streaming_handle_fixed_buffering_mode(streamer, bitrate_info.byte_out_rate, buffering_time, &buffer_info);
825 /*********************************
826 * (2) adaptive mode (default) *
827 *********************************/
828 gint expected_play_time = DEFAULT_PLAYING_TIME;
830 if (streamer->buffering_req.rebuffer_time > 0)
831 expected_play_time = streamer->buffering_req.rebuffer_time;
832 else if ((position == 0) && (streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS))
833 expected_play_time = streamer->buffering_req.prebuffer_time;
835 if (expected_play_time <= 0)
836 expected_play_time = DEFAULT_PLAYING_TIME;
838 streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, expected_play_time);
840 if (IS_MUXED_BUFFERING_MODE(streamer)) // even if new byte size is smaller than the previous one, time need to be updated.
841 buffer_handle->buffering_time = buffer_info.buffering_time;
844 LOGD("adj buffer(%d) %d->%d bytes/%d->%d ms\n",
845 streamer->streaming_buffer_type,
846 GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_info.buffering_bytes,
847 GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_info.buffering_time);
849 /* queue2 : bytes, multiqueue : time */
850 if (((GET_CURRENT_BUFFERING_BYTE(buffer_handle) < buffer_info.buffering_bytes) && IS_MUXED_BUFFERING_MODE(streamer)) ||
851 ((GET_CURRENT_BUFFERING_TIME(buffer_handle) < buffer_info.buffering_time) && IS_DEMUXED_BUFFERING_MODE(streamer))) {
852 if (duration > 0 && position > 0) {
853 gint buffering_time_limit = (gint)(duration - position)/GST_MSECOND;
855 if (buffer_info.buffering_time > buffering_time_limit)
856 buffer_info.buffering_time = buffering_time_limit;
859 streaming_set_buffer_size(streamer, streamer->streaming_buffer_type, buffer_info.buffering_bytes, buffer_info.buffering_time);
862 streaming_set_buffer_percent(streamer, streamer->streaming_buffer_type, low_percent, buffer_info.percent_byte, buffer_info.percent_time);
864 LOGD("buffer setting: size %d, time %d, per %f\n",
865 GET_CURRENT_BUFFERING_BYTE(buffer_handle),
866 GET_CURRENT_BUFFERING_TIME(buffer_handle),
867 buffer_handle->buffer_high_percent);
869 streamer->need_sync = TRUE;
873 streaming_adjust_min_threshold(mm_player_streaming_t* streamer, gint64 position)
875 #define DEFAULT_TIME_PAD 1000 /* ms */
876 gint playing_time = 0;
880 MMPLAYER_RETURN_IF_FAIL(streamer);
882 playing_time = (gint)((position - streamer->default_val.prev_pos) / GST_MSECOND);
884 LOGD("buffering monitor = %s", (streamer->default_val.buffering_monitor) ? "ON" : "OFF");
885 LOGD("playing_time (%d ms) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT, playing_time, position, streamer->default_val.prev_pos);
886 LOGD("default time : %d, prev buffering t : %d",
887 streamer->default_val.buffering_time, streamer->buffer_handle[streamer->streaming_buffer_type].buffering_time);
889 if ((streamer->default_val.buffering_monitor) && (playing_time <= streamer->default_val.buffering_time)) {
891 time_gap = streamer->default_val.buffering_time - DEFAULT_BUFFERING_TIME;
893 time_gap = DEFAULT_TIME_PAD;
895 streamer->default_val.buffering_time += time_gap*2;
896 streamer->default_val.buffering_time = MIN(streamer->default_val.buffering_time, MAX_BUFFERING_TIME);
898 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
901 LOGD("new default min value %d \n", streamer->default_val.buffering_time);
903 streamer->default_val.buffering_monitor = FALSE;
904 streamer->default_val.prev_pos = position;
908 streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position)
910 gint buffer_percent = 0;
914 MMPLAYER_RETURN_IF_FAIL(streamer);
915 MMPLAYER_RETURN_IF_FAIL(buffering_msg);
917 /* update when buffering has started. */
918 if (!(streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
919 streamer->buffering_state = MM_PLAYER_BUFFERING_IN_PROGRESS;
920 streamer->buffering_percent = -1;
922 if (!streamer->buffering_req.is_pre_buffering) {
923 streamer->need_update = TRUE;
924 streaming_adjust_min_threshold(streamer, position);
928 /* update buffer percent */
929 gst_message_parse_buffering(buffering_msg, &buffer_percent);
931 /* LOGD("[%s] buffering per %d%% -> %d%%, state 0x%X", streamer->buffering_percent, buffer_percent, streamer->buffering_state); */
933 if (streamer->buffering_percent < buffer_percent) {
934 LOGD("[%s] buffering %d%%....",
935 GST_OBJECT_NAME(GST_MESSAGE_SRC(buffering_msg)), buffer_percent);
936 streamer->buffering_percent = buffer_percent;
939 if (streamer->buffering_percent == MAX_BUFFER_PERCENT) {
940 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
941 streamer->buffering_req.is_pre_buffering = FALSE;
942 } else if (streamer->buffering_state & MM_PLAYER_BUFFERING_COMPLETE) {
943 streamer->buffering_state = MM_PLAYER_BUFFERING_COMPLETE; /* have to keep state to ignore remained msg till get 100% msg */
944 streamer->buffering_req.is_pre_buffering = FALSE;
945 streamer->buffering_percent = MAX_BUFFER_PERCENT;
946 LOGD("updated to the buffering 100%%.... (by force)");
950 void __mm_player_streaming_buffering(mm_player_streaming_t* streamer,
951 GstMessage *buffering_msg,
952 guint64 content_size,
958 MMPLAYER_RETURN_IF_FAIL(streamer);
959 MMPLAYER_RETURN_IF_FAIL(buffering_msg);
960 MMPLAYER_RETURN_IF_FAIL(GST_IS_MESSAGE(buffering_msg));
961 MMPLAYER_RETURN_IF_FAIL((GST_MESSAGE_TYPE(buffering_msg) == GST_MESSAGE_BUFFERING));
963 if (position > (gint64)(streamer->buffering_req.prebuffer_time * GST_MSECOND))
964 streamer->buffering_req.is_pre_buffering = FALSE;
966 streaming_update_buffering_status(streamer, buffering_msg, position);
968 if (!streamer->need_update)
971 streamer->need_update = FALSE;
972 streaming_update_buffer_setting(streamer, buffering_msg, content_size, position, duration);