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_set_buffer_percent(mm_player_streaming_t* streamer, BufferType type, gdouble high_percent_byte, gdouble high_percent_time);
49 static void streaming_set_queue2_queue_type(mm_player_streaming_t* streamer, MuxedBufferType type, gchar * file_path, guint64 content_size);
50 static void streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gint buffering_time);
51 static void streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position);
52 static void streaming_get_current_bitrate_info(mm_player_streaming_t* streamer,
53 GstMessage *buffering_msg,
54 streaming_content_info_t content_info,
55 streaming_bitrate_info_t* bitrate_info);
57 streaming_handle_fixed_buffering_mode(mm_player_streaming_t* streamer,
59 gint fixed_buffering_time,
60 streaming_buffer_info_t* buffer_info);
62 streaming_handle_adaptive_buffering_mode(mm_player_streaming_t* streamer,
63 streaming_content_info_t content_info,
64 streaming_bitrate_info_t bitrate_info,
65 streaming_buffer_info_t* buffer_info,
66 gint expected_play_time);
68 streaming_update_buffer_setting(mm_player_streaming_t* streamer,
69 GstMessage *buffering_msg,
74 mm_player_streaming_t *
75 __mm_player_streaming_create(void)
77 mm_player_streaming_t *streamer = NULL;
81 streamer = (mm_player_streaming_t *) g_malloc0(sizeof(mm_player_streaming_t));
83 LOGE("fail to create streaming player handle..\n");
93 streaming_buffer_initialize(streaming_buffer_t* buffer_handle, gboolean buffer_init)
96 buffer_handle->buffer = NULL;
98 buffer_handle->buffering_bytes = DEFAULT_BUFFER_SIZE_BYTES;
99 buffer_handle->buffering_time = DEFAULT_BUFFERING_TIME;
100 buffer_handle->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
101 buffer_handle->is_live = FALSE;
105 void __mm_player_streaming_initialize(mm_player_streaming_t* streamer)
109 streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue
111 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), TRUE);
112 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), TRUE);
114 streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
115 streamer->buffering_req.is_pre_buffering = FALSE;
116 streamer->buffering_req.prebuffer_time = 0;
117 streamer->buffering_req.rebuffer_time = 0;
119 streamer->default_val.buffering_monitor = FALSE;
120 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
122 streamer->buffer_avg_bitrate = 0;
123 streamer->buffer_max_bitrate = 0;
124 streamer->need_update = FALSE;
125 streamer->need_sync = FALSE;
127 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
128 streamer->is_adaptive_streaming = FALSE;
130 streamer->buffering_percent = -1;
131 streamer->ring_buffer_size = DEFAULT_RING_BUFFER_SIZE;
137 void __mm_player_streaming_deinitialize(mm_player_streaming_t* streamer)
140 MMPLAYER_RETURN_IF_FAIL(streamer);
142 streamer->streaming_buffer_type = BUFFER_TYPE_DEFAULT; // multi-queue
144 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_MUXED]), FALSE);
145 streaming_buffer_initialize(&(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]), FALSE);
147 streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
148 streamer->buffering_req.is_pre_buffering = FALSE;
149 streamer->buffering_req.prebuffer_time = 0;
150 streamer->buffering_req.rebuffer_time = 0;
152 streamer->default_val.buffering_monitor = FALSE;
153 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
155 streamer->buffer_avg_bitrate = 0;
156 streamer->buffer_max_bitrate = 0;
157 streamer->need_update = FALSE;
158 streamer->need_sync = FALSE;
160 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
161 streamer->is_adaptive_streaming = FALSE;
163 streamer->buffering_percent = -1;
164 streamer->ring_buffer_size = DEFAULT_RING_BUFFER_SIZE;
170 void __mm_player_streaming_destroy(mm_player_streaming_t* streamer)
181 void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate)
185 MMPLAYER_RETURN_IF_FAIL(streamer);
187 /* Note : Update buffering criterion bytes
188 * 1. maximum bitrate is considered first.
189 * 2. average bitrage * 3 is next.
190 * 3. if there are no updated bitrate, use default buffering limit.
192 if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate) {
193 LOGD("set maximum bitrate(%dbps).\n", max_bitrate);
194 streamer->buffer_max_bitrate = max_bitrate;
195 if (streamer->buffering_req.is_pre_buffering == FALSE) {
196 streamer->need_update = TRUE;
198 LOGD("pre-buffering...\n");
200 if (IS_MUXED_BUFFERING_MODE(streamer))
201 streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
205 if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate) {
206 LOGD("set averate bitrate(%dbps).\n", avg_bitrate);
207 streamer->buffer_avg_bitrate = avg_bitrate;
209 if (streamer->buffering_req.is_pre_buffering == FALSE) {
210 streamer->need_update = TRUE;
212 LOGD("pre-buffering...\n");
214 if (IS_MUXED_BUFFERING_MODE(streamer))
215 streaming_update_buffer_setting(streamer, NULL, 0, 0, 0);
224 streaming_set_buffer_percent(mm_player_streaming_t* streamer,
226 gdouble high_percent_byte,
227 gdouble high_percent_time)
229 gdouble high_percent = 0.0;
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 (type == BUFFER_TYPE_MUXED)
252 high_percent = high_percent_byte;
254 high_percent = MAX(high_percent_time, high_percent_byte);
256 if (high_percent <= MIN_BUFFER_PERCENT || high_percent >= MAX_BUFFER_PERCENT)
257 high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
259 /* if use-buffering is disabled, this settings do not have any meaning. */
260 LOGD("target buffer elem : %s (~ %2.3f)",
261 GST_ELEMENT_NAME(buffer_handle->buffer), high_percent);
263 if ((high_percent == DEFAULT_BUFFER_HIGH_PERCENT) ||
264 (buffer_handle->buffer_high_percent != high_percent))
265 g_object_set(G_OBJECT(buffer_handle->buffer), "high-percent", (gint)high_percent, NULL);
267 buffer_handle->buffer_high_percent = high_percent;
274 streaming_set_queue2_queue_type(mm_player_streaming_t* streamer, MuxedBufferType type, gchar * file_path, guint64 content_size)
276 streaming_buffer_t* buffer_handle = NULL;
277 guint64 storage_available_size = 0; /* bytes */
278 guint64 buffer_size = 0; /* bytes */
279 gchar file_buffer_name[MM_MAX_URL_LEN] = {0};
280 struct statfs buf = {0};
281 gchar* factory_name = NULL;
284 MMPLAYER_RETURN_IF_FAIL(streamer);
285 MMPLAYER_RETURN_IF_FAIL(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer);
287 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_MUXED]);
289 if (!(buffer_handle && buffer_handle->buffer)) {
290 LOGE("buffer_handle->buffer is NULL!");
294 factory_name = GST_OBJECT_NAME(gst_element_get_factory(buffer_handle->buffer));
297 LOGE("Fail to get factory name!");
301 LOGD("target buffer elem : %s", GST_ELEMENT_NAME(buffer_handle->buffer));
303 if (!g_strrstr(factory_name, "queue2")) {
304 LOGD("only queue2 can use file buffer. not decodebin2 or multiQ\n");
308 if (type == MUXED_BUFFER_TYPE_MEM_QUEUE) {
309 LOGD("use memory queue for buffering. streaming is played on push-based. \n"
310 "buffering position would not be updated.\n"
311 "buffered data would be flushed after played.\n"
312 "seeking and getting duration could be failed due to file format.");
316 LOGD("[Queue2] buffering type : %d. streaming is played on pull-based. \n", type);
317 if (type == MUXED_BUFFER_TYPE_FILE && file_path && strlen(file_path) > 0) {
318 if (statfs((const char *)file_path, &buf) < 0) {
319 LOGW("[Queue2] fail to get available storage capacity. set mem ring buffer instead of file buffer.\n");
320 buffer_size = (guint64)((streamer->ring_buffer_size > 0) ? (streamer->ring_buffer_size) : DEFAULT_RING_BUFFER_SIZE);
322 storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes
324 LOGD("[Queue2] the number of available blocks : %"G_GUINT64_FORMAT
325 ", the block size is %"G_GUINT64_FORMAT".\n",
326 (guint64)buf.f_bavail, (guint64)buf.f_bsize);
328 LOGD("[Queue2] calculated available storage size is %"
329 G_GUINT64_FORMAT" Bytes.\n", storage_available_size);
331 if (content_size <= 0 || content_size >= storage_available_size)
332 buffer_size = storage_available_size;
336 g_snprintf(file_buffer_name, MM_MAX_URL_LEN, "%sXXXXXX", file_path);
337 SECURE_LOGD("[Queue2] the buffering file name is %s.\n", file_buffer_name);
339 g_object_set(G_OBJECT(buffer_handle->buffer), "temp-template", file_buffer_name, NULL);
342 buffer_size = (guint64)((streamer->ring_buffer_size > 0) ? (streamer->ring_buffer_size) : DEFAULT_RING_BUFFER_SIZE);
345 LOGW("[Queue2] set ring buffer size: %"G_GUINT64_FORMAT, buffer_size);
346 g_object_set(G_OBJECT(buffer_handle->buffer), "ring-buffer-max-size", buffer_size, NULL);
353 streaming_set_buffer_size(mm_player_streaming_t* streamer, BufferType type, guint buffering_bytes, gint buffering_time)
355 streaming_buffer_t* buffer_handle = NULL;
359 MMPLAYER_RETURN_IF_FAIL(streamer);
360 MMPLAYER_RETURN_IF_FAIL(buffering_bytes > 0);
361 MMPLAYER_RETURN_IF_FAIL(type < BUFFER_TYPE_MAX);
363 buffer_handle = &(streamer->buffer_handle[type]);
365 if (buffer_handle && buffer_handle->buffer) {
366 if (g_strrstr(GST_ELEMENT_NAME(buffer_handle->buffer), "multiqueue")) {
367 if (buffering_time <= 0)
368 buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
370 g_object_set(G_OBJECT(buffer_handle->buffer),
371 "max-size-bytes", GET_MAX_BUFFER_BYTES(streamer), /* mq size is fixed, control it with high/low percent value*/
372 "max-size-time", (guint64)(buffering_time * GST_MSECOND),
373 "max-size-buffers", 0, NULL); /* disable */
375 buffer_handle->buffering_time = buffering_time;
376 buffer_handle->buffering_bytes = GET_MAX_BUFFER_BYTES(streamer);
378 LOGD("max-size-time : %d ms", buffering_time);
381 if (buffer_handle->is_live)
382 g_object_set(G_OBJECT(buffer_handle->buffer),
383 "max-size-bytes", buffering_bytes,
384 "max-size-time", (guint64)(buffering_time*GST_MSECOND),
385 "max-size-buffers", 0,
386 "use-rate-estimate", TRUE, NULL);
388 g_object_set(G_OBJECT(buffer_handle->buffer),
389 "max-size-bytes", buffering_bytes,
390 "max-size-time", (guint64)0,
391 "max-size-buffers", 0,
392 "use-rate-estimate", FALSE, NULL);
394 buffer_handle->buffering_bytes = buffering_bytes;
395 buffer_handle->buffering_time = buffering_time;
397 LOGD("max-size-bytes : %d", buffering_bytes);
405 void __mm_player_streaming_set_queue2(mm_player_streaming_t* streamer,
407 gboolean use_buffering,
408 guint buffering_bytes,
410 MuxedBufferType type,
412 guint64 content_size)
415 MMPLAYER_RETURN_IF_FAIL(streamer);
418 LOGD("USE-BUFFERING : %s", (use_buffering) ? "OOO" : "XXX");
420 streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer = buffer;
423 streamer->streaming_buffer_type = BUFFER_TYPE_MUXED;
425 if (content_size > 0) {
426 if (streamer->buffering_req.prebuffer_time > 0)
427 streamer->buffering_req.is_pre_buffering = TRUE;
429 streamer->buffering_req.prebuffer_time = buffering_time;
431 LOGD("live streaming without mq");
433 streamer->buffer_handle[BUFFER_TYPE_MUXED].is_live = TRUE;
434 streamer->buffering_req.prebuffer_time = buffering_time = DEFAULT_BUFFERING_TIME;
438 g_object_set(G_OBJECT(streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), "use-buffering", use_buffering, NULL);
441 /* initial setting */
442 streaming_set_buffer_size(streamer, BUFFER_TYPE_MUXED, buffering_bytes, buffering_time);
443 streaming_set_buffer_percent(streamer, BUFFER_TYPE_MUXED, DEFAULT_BUFFER_HIGH_PERCENT, 0);
444 if (type < MUXED_BUFFER_TYPE_MAX)
445 streaming_set_queue2_queue_type(streamer, type, file_path, content_size);
451 void __mm_player_streaming_sync_property(mm_player_streaming_t* streamer, GstElement* decodebin)
453 streaming_buffer_t* buffer_handle = NULL;
457 MMPLAYER_RETURN_IF_FAIL(streamer && decodebin);
459 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
461 if ((streamer->need_sync) && (streamer->streaming_buffer_type == BUFFER_TYPE_DEMUXED)) {
462 g_object_set(G_OBJECT(decodebin),
463 "max-size-bytes", buffer_handle->buffering_bytes,
464 "max-size-time", (guint64)(buffer_handle->buffering_time * GST_MSECOND),
465 "high-percent", (gint)buffer_handle->buffer_high_percent, NULL);
468 streamer->need_sync = FALSE;
471 void __mm_player_streaming_set_multiqueue(mm_player_streaming_t* streamer,
475 streaming_buffer_t* buffer_handle = NULL;
476 gdouble high_percent = 0.0;
479 MMPLAYER_RETURN_IF_FAIL(streamer && buffer);
481 buffer_handle = &(streamer->buffer_handle[BUFFER_TYPE_DEMUXED]);
483 buffer_handle->buffer = buffer;
485 streamer->streaming_buffer_type = BUFFER_TYPE_DEMUXED;
486 g_object_set(G_OBJECT(buffer_handle->buffer), "use-buffering", TRUE, NULL);
489 LOGD("pre_buffering: %d ms, during playing: %d ms\n", streamer->buffering_req.prebuffer_time, buffering_time);
491 if (streamer->buffering_req.prebuffer_time > 0)
492 streamer->buffering_req.is_pre_buffering = TRUE;
494 streamer->buffering_req.prebuffer_time = GET_DEFAULT_PLAYING_TIME(streamer);
496 high_percent = (gdouble)(streamer->buffering_req.prebuffer_time * 100) / GET_MAX_BUFFER_TIME(streamer);
497 LOGD("high_percent %2.3f %%\n", high_percent);
499 /* initial setting */
500 streaming_set_buffer_size(streamer, BUFFER_TYPE_DEMUXED, GET_MAX_BUFFER_BYTES(streamer), GET_MAX_BUFFER_TIME(streamer));
501 streaming_set_buffer_percent(streamer, BUFFER_TYPE_DEMUXED, 0, high_percent);
503 streamer->need_sync = TRUE;
510 streaming_get_current_bitrate_info(mm_player_streaming_t* streamer,
511 GstMessage *buffering_msg,
512 streaming_content_info_t content_info,
513 streaming_bitrate_info_t* bitrate_info)
516 GstQuery *query = NULL;
517 GstBufferingMode mode = GST_BUFFERING_STREAM;
520 gint64 buffering_left = -1;
522 guint buffer_criteria = 0;
523 guint estimated_content_bitrate = 0;
525 gint buffer_buffering_time = DEFAULT_BUFFERING_TIME;
529 MMPLAYER_RETURN_IF_FAIL(streamer);
530 MMPLAYER_RETURN_IF_FAIL(bitrate_info);
532 if ((buffering_msg == NULL) ||
533 ((streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer != NULL) &&
534 (streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer != NULL) &&
535 (buffering_msg->src == (GstObject *)streamer->buffer_handle[BUFFER_TYPE_DEMUXED].buffer))) {
536 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
538 if (gst_element_query((streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), query))
539 gst_query_parse_buffering_stats(query, &mode, &in_rate, &out_rate, &buffering_left);
540 gst_query_unref(query);
542 gst_message_parse_buffering_stats(buffering_msg, &mode, &in_rate, &out_rate, &buffering_left);
545 LOGD("Streaming Info : in %d, out %d, left %"G_GINT64_FORMAT, in_rate, out_rate, buffering_left);
547 if ((content_info.content_size > 0) && (content_info.duration > 0) && ((content_info.duration/GST_SECOND) > 0))
548 estimated_content_bitrate = GET_BIT_FROM_BYTE((guint)(content_info.content_size / (content_info.duration/GST_SECOND)));
550 if (streamer->buffer_max_bitrate > 0) {
551 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, streamer->buffer_avg_bitrate);
552 streamer->buffer_max_bitrate = MAX(streamer->buffer_max_bitrate, estimated_content_bitrate);
554 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate);
556 if (streamer->buffer_avg_bitrate > estimated_content_bitrate)
557 out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate);
558 else if (estimated_content_bitrate != 0)
559 out_rate = GET_BYTE_FROM_BIT(estimated_content_bitrate);
561 out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate/3);
563 LOGD("(max)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate);
564 } else if (streamer->buffer_avg_bitrate > 0) {
565 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3);
566 out_rate = GET_BYTE_FROM_BIT(MAX(streamer->buffer_avg_bitrate, estimated_content_bitrate));
568 LOGD("(avg)content_max_byte_rate %d, byte_out_rate %d\n", buffer_criteria, out_rate);
570 LOGW("There is no content bitrate information\n");
573 if ((in_rate > 0) && (out_rate > 0))
574 buffer_buffering_time = (gint)(out_rate / in_rate)*1000;
575 else if ((in_rate <= 0) && (out_rate > 0))
576 buffer_buffering_time = MAX_BUFFERING_TIME;
578 buffer_buffering_time = DEFAULT_BUFFERING_TIME;
580 (*bitrate_info).byte_in_rate = in_rate;
581 (*bitrate_info).byte_out_rate = out_rate;
582 (*bitrate_info).time_rate = buffer_buffering_time;
583 (*bitrate_info).buffer_criteria = buffer_criteria;
587 streaming_handle_fixed_buffering_mode(mm_player_streaming_t* streamer,
589 gint fixed_buffering_time,
590 streaming_buffer_info_t* buffer_info)
592 streaming_buffer_t* buffer_handle = NULL;
594 guint buffering_bytes = 0;
595 gint buffering_time = 0;
596 gdouble per_byte = 0.0;
597 gdouble per_time = 0.0;
599 MMPLAYER_RETURN_IF_FAIL(streamer);
600 MMPLAYER_RETURN_IF_FAIL(buffer_info);
602 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
603 buffering_time = fixed_buffering_time;
605 LOGD("buffering time: %d ms, out rate: %d\n", buffering_time, byte_out_rate);
607 if ((buffering_time > 0) && (byte_out_rate > 0)) {
608 buffering_bytes = (guint)GET_NEW_BUFFERING_BYTE((gdouble)(byte_out_rate * buffering_time)/1000);
610 if (buffering_time <= 0)
611 buffering_time = GET_CURRENT_BUFFERING_TIME(buffer_handle);
613 LOGW("content bitrate is not updated yet.\n");
614 buffering_bytes = GET_CURRENT_BUFFERING_BYTE(buffer_handle);
617 GET_PERCENT(buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time);
618 GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte);
620 LOGD("bytes %d, time %d, per_byte %f, per_time %f\n", buffering_bytes, buffering_time, per_byte, per_time);
622 (*buffer_info).buffering_bytes = buffering_bytes;
623 (*buffer_info).buffering_time = buffering_time;
624 (*buffer_info).percent_byte = per_byte;
625 (*buffer_info).percent_time = per_time;
629 streaming_handle_adaptive_buffering_mode(mm_player_streaming_t* streamer,
630 streaming_content_info_t content_info,
631 streaming_bitrate_info_t bitrate_info,
632 streaming_buffer_info_t* buffer_info,
633 gint expected_play_time)
635 streaming_buffer_t* buffer_handle = NULL;
637 gint buffering_bytes = 0;
638 gint adj_buffering_bytes = 0;
639 gint buffer_buffering_time = 0;
640 gdouble per_byte = 0.0;
641 gdouble per_time = 0.0;
642 gdouble portion = 0.0;
643 gint default_buffering_time = 0;
645 MMPLAYER_RETURN_IF_FAIL(streamer);
646 MMPLAYER_RETURN_IF_FAIL(buffer_info);
648 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",
649 content_info.position, content_info.duration, content_info.content_size,
650 bitrate_info.byte_in_rate, bitrate_info.byte_out_rate,
651 bitrate_info.buffer_criteria, bitrate_info.time_rate, expected_play_time);
653 if ((content_info.duration <= 0) ||
654 (content_info.content_size <= 0)) {
655 LOGW("keep previous setting.\n");
659 if ((bitrate_info.byte_out_rate <= 0) || (bitrate_info.buffer_criteria == 0)) {
660 LOGW("keep previous setting.\n");
664 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
666 if (bitrate_info.byte_in_rate < bitrate_info.byte_out_rate) {
667 portion = (double)(expected_play_time * GST_MSECOND) / (double)content_info.duration;
668 buffering_bytes = GET_NEW_BUFFERING_BYTE(((double)content_info.content_size * portion) \
669 * (1 - (double)bitrate_info.byte_in_rate/(double)bitrate_info.byte_out_rate));
671 /* buffering_bytes will be set as streamer->default_val.buffering_time *
672 * receiving rate is bigger than avg content bitrate
673 * so there is no reason to buffering. if the buffering msg is posted
674 * in-rate or contents bitrate has wrong value. */
675 LOGW("don't need to do buffering.\n");
678 if (buffering_bytes > 0)
679 buffer_buffering_time = (gint)(buffering_bytes / bitrate_info.byte_out_rate)*1000;
681 if (content_info.position <= 0) {
682 /* if the buffer is filled under 50%, MSL use the original default buffering time.
683 if not, MSL use just 2 sec as a default buffering time. (to reduce initial buffering time) */
684 default_buffering_time = streamer->default_val.buffering_time - ((gdouble)streamer->buffering_percent/50)*1000;
686 default_buffering_time = streamer->default_val.buffering_time;
689 if (buffer_buffering_time < default_buffering_time) {
690 LOGD("adjusted time: %d -> %d ms\n", buffer_buffering_time, default_buffering_time);
691 LOGD("adjusted bytes : %d or %d or %d\n",
693 (gint)(bitrate_info.byte_out_rate * buffer_buffering_time/1000),
694 (gint)(bitrate_info.buffer_criteria * buffer_buffering_time/1000));
696 /* start monitoring the abmormal state */
697 if (content_info.position > 0)
698 streamer->default_val.buffering_monitor = TRUE;
700 buffer_buffering_time = default_buffering_time;
701 adj_buffering_bytes = GET_NEW_BUFFERING_BYTE(bitrate_info.byte_out_rate * (gint)ceil((gdouble)buffer_buffering_time/1000));
702 buffering_bytes = MAX(buffering_bytes, adj_buffering_bytes);
705 GET_PERCENT(buffering_bytes, GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_handle->buffer_high_percent, per_byte);
706 GET_PERCENT(buffer_buffering_time, GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_handle->buffer_high_percent, per_time);
708 LOGD("monitor %d, bytes %d, time %d, per_byte %f, per_time %f\n",
709 streamer->default_val.buffering_monitor,
710 buffering_bytes, buffer_buffering_time, per_byte, per_time);
712 (*buffer_info).buffering_bytes = buffering_bytes;
713 (*buffer_info).buffering_time = buffer_buffering_time;
714 (*buffer_info).percent_byte = per_byte;
715 (*buffer_info).percent_time = per_time;
720 streaming_update_buffer_setting(mm_player_streaming_t* streamer,
721 GstMessage *buffering_msg, /* can be null */
722 guint64 content_size,
726 streaming_buffer_t* buffer_handle = NULL;
727 MMPlayerBufferingMode buffering_mode = MM_PLAYER_BUFFERING_MODE_ADAPTIVE;
729 streaming_buffer_info_t buffer_info;
730 streaming_content_info_t content_info;
731 streaming_bitrate_info_t bitrate_info;
735 MMPLAYER_RETURN_IF_FAIL(streamer);
737 memset(&buffer_info, 0x00, sizeof(streaming_buffer_info_t));
738 memset(&content_info, 0x00, sizeof(streaming_content_info_t));
739 memset(&bitrate_info, 0x00, sizeof(streaming_bitrate_info_t));
741 buffer_handle = &(streamer->buffer_handle[streamer->streaming_buffer_type]);
743 if (streamer->buffering_req.is_pre_buffering == TRUE)
744 buffering_mode = MM_PLAYER_BUFFERING_MODE_FIXED;
746 buffering_mode = streamer->buffering_req.mode;
748 buffer_info.buffering_bytes = buffer_handle->buffering_bytes;
749 buffer_info.buffering_time = buffer_handle->buffering_time;
750 buffer_info.percent_byte = buffer_handle->buffer_high_percent;
751 buffer_info.percent_time = buffer_handle->buffer_high_percent;
753 content_info.position = position;
754 content_info.duration = duration;
755 content_info.content_size = content_size;
757 streaming_get_current_bitrate_info(streamer, buffering_msg, content_info, &bitrate_info);
759 LOGD("buffering mode %d, new info in_r:%d, out_r:%d, cb:%d, bt:%d\n",
760 buffering_mode, bitrate_info.byte_in_rate, bitrate_info.byte_out_rate,
761 bitrate_info.buffer_criteria, bitrate_info.time_rate);
763 if (buffering_mode == MM_PLAYER_BUFFERING_MODE_FIXED) {
764 /********************
766 ********************/
767 gint buffering_time = 0;
769 if (streamer->buffering_req.is_pre_buffering == TRUE)
770 buffering_time = streamer->buffering_req.prebuffer_time;
772 buffering_time = streamer->buffering_req.rebuffer_time;
774 streaming_handle_fixed_buffering_mode(streamer, bitrate_info.byte_out_rate, buffering_time, &buffer_info);
776 /*********************************
777 * (2) adaptive mode (default) *
778 *********************************/
779 gint expected_play_time = DEFAULT_PLAYING_TIME;
781 if (streamer->buffering_req.rebuffer_time > 0)
782 expected_play_time = streamer->buffering_req.rebuffer_time;
783 else if ((position == 0) && (streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS))
784 expected_play_time = streamer->buffering_req.prebuffer_time;
786 if (expected_play_time <= 0)
787 expected_play_time = DEFAULT_PLAYING_TIME;
789 streaming_handle_adaptive_buffering_mode(streamer, content_info, bitrate_info, &buffer_info, expected_play_time);
791 if (IS_MUXED_BUFFERING_MODE(streamer)) // even if new byte size is smaller than the previous one, time need to be updated.
792 buffer_handle->buffering_time = buffer_info.buffering_time;
795 LOGD("adj buffer(%d) %d->%d bytes/%d->%d ms\n",
796 streamer->streaming_buffer_type,
797 GET_CURRENT_BUFFERING_BYTE(buffer_handle), buffer_info.buffering_bytes,
798 GET_CURRENT_BUFFERING_TIME(buffer_handle), buffer_info.buffering_time);
800 /* queue2 : bytes, multiqueue : time */
801 if (((GET_CURRENT_BUFFERING_BYTE(buffer_handle) < buffer_info.buffering_bytes) && IS_MUXED_BUFFERING_MODE(streamer)) ||
802 ((GET_CURRENT_BUFFERING_TIME(buffer_handle) < buffer_info.buffering_time) && IS_DEMUXED_BUFFERING_MODE(streamer))) {
803 if (duration > 0 && position > 0) {
804 gint buffering_time_limit = (gint)(duration - position)/GST_MSECOND;
806 if (buffer_info.buffering_time > buffering_time_limit)
807 buffer_info.buffering_time = buffering_time_limit;
810 streaming_set_buffer_size(streamer, streamer->streaming_buffer_type, buffer_info.buffering_bytes, buffer_info.buffering_time);
813 streaming_set_buffer_percent(streamer, streamer->streaming_buffer_type, buffer_info.percent_byte, buffer_info.percent_time);
815 LOGD("buffer setting: size %d, time %d, per %f\n",
816 GET_CURRENT_BUFFERING_BYTE(buffer_handle),
817 GET_CURRENT_BUFFERING_TIME(buffer_handle),
818 buffer_handle->buffer_high_percent);
820 streamer->need_sync = TRUE;
824 streaming_adjust_min_threshold(mm_player_streaming_t* streamer, gint64 position)
826 #define DEFAULT_TIME_PAD 1000 /* ms */
827 gint playing_time = 0;
831 MMPLAYER_RETURN_IF_FAIL(streamer);
833 playing_time = (gint)((position - streamer->default_val.prev_pos) / GST_MSECOND);
835 LOGD("buffering monitor = %s", (streamer->default_val.buffering_monitor) ? "ON" : "OFF");
836 LOGD("playing_time (%d ms) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT, playing_time, position, streamer->default_val.prev_pos);
837 LOGD("default time : %d, prev buffering t : %d",
838 streamer->default_val.buffering_time, streamer->buffer_handle[streamer->streaming_buffer_type].buffering_time);
840 if ((streamer->default_val.buffering_monitor) && (playing_time <= streamer->default_val.buffering_time)) {
842 time_gap = streamer->default_val.buffering_time - DEFAULT_BUFFERING_TIME;
844 time_gap = DEFAULT_TIME_PAD;
846 streamer->default_val.buffering_time += time_gap*2;
847 streamer->default_val.buffering_time = MIN(streamer->default_val.buffering_time, MAX_BUFFERING_TIME);
849 streamer->default_val.buffering_time = DEFAULT_BUFFERING_TIME;
852 LOGD("new default min value %d \n", streamer->default_val.buffering_time);
854 streamer->default_val.buffering_monitor = FALSE;
855 streamer->default_val.prev_pos = position;
859 streaming_update_buffering_status(mm_player_streaming_t* streamer, GstMessage *buffering_msg, gint64 position)
861 gint buffer_percent = 0;
865 MMPLAYER_RETURN_IF_FAIL(streamer);
866 MMPLAYER_RETURN_IF_FAIL(buffering_msg);
868 /* update when buffering has started. */
869 if (!(streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
870 streamer->buffering_state = MM_PLAYER_BUFFERING_IN_PROGRESS;
871 streamer->buffering_percent = -1;
873 if (!streamer->buffering_req.is_pre_buffering) {
874 streamer->need_update = TRUE;
875 streaming_adjust_min_threshold(streamer, position);
879 /* update buffer percent */
880 gst_message_parse_buffering(buffering_msg, &buffer_percent);
882 /* LOGD("[%s] buffering per %d%% -> %d%%, state 0x%X", streamer->buffering_percent, buffer_percent, streamer->buffering_state); */
884 if (streamer->buffering_percent < buffer_percent) {
885 LOGD("[%s] buffering %d%%....",
886 GST_OBJECT_NAME(GST_MESSAGE_SRC(buffering_msg)), buffer_percent);
887 streamer->buffering_percent = buffer_percent;
890 if (streamer->buffering_percent == MAX_BUFFER_PERCENT) {
891 streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
892 streamer->buffering_req.is_pre_buffering = FALSE;
893 } else if (streamer->buffering_state & MM_PLAYER_BUFFERING_COMPLETE) {
894 streamer->buffering_state = MM_PLAYER_BUFFERING_COMPLETE; /* have to keep state to ignore remained msg till get 100% msg */
895 streamer->buffering_req.is_pre_buffering = FALSE;
896 streamer->buffering_percent = MAX_BUFFER_PERCENT;
897 LOGD("updated to the buffering 100%%.... (by force)");
901 void __mm_player_streaming_buffering(mm_player_streaming_t* streamer,
902 GstMessage *buffering_msg,
903 guint64 content_size,
909 MMPLAYER_RETURN_IF_FAIL(streamer);
910 MMPLAYER_RETURN_IF_FAIL(buffering_msg);
911 MMPLAYER_RETURN_IF_FAIL(GST_IS_MESSAGE(buffering_msg));
912 MMPLAYER_RETURN_IF_FAIL((GST_MESSAGE_TYPE(buffering_msg) == GST_MESSAGE_BUFFERING));
914 if (position > (gint64)(streamer->buffering_req.prebuffer_time * GST_MSECOND))
915 streamer->buffering_req.is_pre_buffering = FALSE;
917 streaming_update_buffering_status(streamer, buffering_msg, position);
919 if (!streamer->need_update)
922 streamer->need_update = FALSE;
923 streaming_update_buffer_setting(streamer, buffering_msg, content_size, position, duration);