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>, YoungHwan An <younghwan_.an@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
23 #include "mm_player_utils.h"
25 #include "mm_player_streaming.h"
27 static void streaming_set_buffer_size(mm_player_streaming_t* streamer, guint buffer_size);
28 static void streaming_set_buffer_percent(mm_player_streaming_t* streamer, gdouble low_percent, gdouble high_percent);
29 static void streaming_set_buffer_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size);
30 static void streaming_set_buffering_time(mm_player_streaming_t* streamer, gdouble buffering_time);
33 mm_player_streaming_t *
34 __mm_player_streaming_create ()
36 mm_player_streaming_t *streamer = NULL;
40 streamer = (mm_player_streaming_t *) malloc (sizeof (mm_player_streaming_t));
43 debug_error ("fail to create streaming player handle..\n");
52 void __mm_player_streaming_initialize (mm_player_streaming_t* streamer)
56 streamer->buffer = NULL;
57 streamer->buffer_size = DEFAULT_BUFFER_SIZE;
58 streamer->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
59 streamer->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
60 streamer->buffer_avg_bitrate = 0;
61 streamer->buffer_max_bitrate = 0;
62 streamer->need_update = FALSE;
64 streamer->is_buffering = FALSE;
65 streamer->buffering_percent = -1;
66 streamer->buffering_time = DEFAULT_BUFFERING_TIME;
73 void __mm_player_streaming_deinitialize (mm_player_streaming_t* streamer)
77 return_if_fail(streamer);
79 streamer->buffer_size = DEFAULT_BUFFER_SIZE;
80 streamer->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
81 streamer->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
82 streamer->buffer_avg_bitrate = 0;
83 streamer->buffer_max_bitrate = 0;
84 streamer->need_update = FALSE;
86 streamer->is_buffering = FALSE;
87 streamer->buffering_percent = -1;
88 streamer->buffering_time = DEFAULT_BUFFERING_TIME;
95 void __mm_player_streaming_destroy (mm_player_streaming_t* streamer)
110 void __mm_player_streaming_set_buffer(mm_player_streaming_t* streamer, GstElement * buffer,
111 gboolean use_buffering, guint buffer_size, gdouble low_percent, gdouble high_percent, gdouble buffering_time,
112 gboolean use_file, gchar * file_path, guint64 content_size)
116 return_if_fail(streamer);
120 streamer->buffer = buffer;
122 debug_log("buffer element is %s.", GST_ELEMENT_NAME(buffer));
124 g_object_set ( G_OBJECT (streamer->buffer), "use-buffering", use_buffering, NULL );
127 streaming_set_buffer_size(streamer, buffer_size);
128 streaming_set_buffer_percent(streamer, low_percent, high_percent);
129 streaming_set_buffer_type (streamer, use_file, file_path, content_size);
130 streaming_set_buffering_time(streamer, buffering_time);
137 void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate)
141 return_if_fail(streamer);
143 /* Note : Update buffering criterion bytes
144 * 1. maximum bitrate is considered first.
145 * 2. average bitrage * 3 is next.
146 * 3. if there are no updated bitrate, use default buffering limit.
148 if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate)
150 debug_log("set maximum bitrate(%dbps).\n", max_bitrate);
151 streamer->buffer_max_bitrate = max_bitrate;
153 streamer->need_update = TRUE;
156 if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate)
158 debug_log("set averate bitrate(%dbps).\n", avg_bitrate);
159 streamer->buffer_avg_bitrate = avg_bitrate;
161 streamer->need_update = TRUE;
170 streaming_set_buffer_size(mm_player_streaming_t* streamer, guint buffer_size)
174 return_if_fail(streamer);
175 return_if_fail(buffer_size>0);
177 debug_log("set buffer size to %d.", buffer_size);
179 streamer->buffer_size = buffer_size;
181 if (streamer->buffer)
182 g_object_set (G_OBJECT(streamer->buffer), "max-size-bytes", buffer_size, NULL);
190 streaming_set_buffer_percent(mm_player_streaming_t* streamer, gdouble low_percent, gdouble high_percent)
192 gdouble buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
193 gdouble buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
197 return_if_fail(streamer);
199 if (low_percent <= MIN_BUFFER_PERCENT || low_percent >= MAX_BUFFER_PERCENT)
201 debug_warning("buffer low percent is out of range. use defaut value.");
202 buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
206 buffer_low_percent = low_percent;
209 if (high_percent <= MIN_BUFFER_PERCENT || high_percent >= MAX_BUFFER_PERCENT)
211 debug_warning("buffer high percent is out of range. use defaut value.");
212 buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
216 buffer_high_percent = high_percent;
219 if (buffer_high_percent <= buffer_low_percent)
220 buffer_high_percent = buffer_low_percent + 1.0;
222 debug_log("set buffer percent to %2.3f ~ %2.3f.", streamer->buffer_low_percent, streamer->buffer_high_percent);
224 if (streamer->buffer)
226 if ( streamer->buffer_low_percent != buffer_low_percent )
227 g_object_set (G_OBJECT(streamer->buffer), "low-percent", streamer->buffer_low_percent, NULL);
229 if ( streamer->buffer_high_percent != buffer_high_percent )
230 g_object_set (G_OBJECT(streamer->buffer), "high-percent", streamer->buffer_high_percent, NULL);
233 streamer->buffer_low_percent = buffer_low_percent;
234 streamer->buffer_high_percent = buffer_high_percent;
242 streaming_set_buffering_time(mm_player_streaming_t* streamer, gdouble buffering_time)
244 gdouble buffer_buffering_time = DEFAULT_BUFFERING_TIME;
248 return_if_fail(streamer);
250 if (buffering_time < MIN_BUFFERING_TIME)
251 buffer_buffering_time = MIN_BUFFERING_TIME;
252 else if (buffering_time > MAX_BUFFERING_TIME)
253 buffer_buffering_time = MAX_BUFFERING_TIME;
255 buffer_buffering_time = buffering_time;
257 if (streamer->buffering_time != buffer_buffering_time)
259 debug_log("set buffer buffering time from %2.1f to %2.1f.", streamer->buffering_time, buffer_buffering_time);
261 streamer->buffering_time = buffer_buffering_time;
270 streaming_set_buffer_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size)
272 guint64 storage_available_size = 0L; //bytes
273 guint64 file_buffer_size = 0L; //bytes
274 gchar file_buffer_name[MAX_FILE_BUFFER_NAME_LEN] = {0};
275 struct statfs buf = {0};
279 return_if_fail(streamer && streamer->buffer);
283 debug_log("use memory for buffering. streaming is played on push-based. \n"
284 "buffering position would not be updated.\n"
285 "buffered data would be flushed after played.\n"
286 "seeking and getting duration could be failed due to file format.");
290 debug_log("use file for buffering. streaming is played on pull-based. \n");
292 if (!file_path || strlen(file_path) <= 0)
293 file_path = g_strdup(DEFAULT_FILE_BUFFER_PATH);
295 g_snprintf(file_buffer_name, MM_MAX_URL_LEN, "%s/XXXXXX", file_path);
296 debug_log("the buffering file name is %s.\n", file_buffer_name);
298 if (statfs((const char *)file_path, &buf) < 0)
300 debug_warning ("fail to get availabe storage capacity. just use file buffer.\n");
301 file_buffer_size = 0L;
305 storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes
307 debug_log ("the number of available blocks : %"G_GUINT64_FORMAT", the block size is %"G_GUINT64_FORMAT".\n",
308 (guint64)buf.f_bavail, (guint64)buf.f_bsize);
309 debug_log ("calculated availabe storage size is %"G_GUINT64_FORMAT" Bytes.\n", storage_available_size);
311 if (content_size <= 0 || content_size >= storage_available_size)
312 file_buffer_size = storage_available_size;
314 file_buffer_size = 0L;
317 if (file_buffer_size>0)
318 debug_log("use file ring buffer for buffering.");
320 g_object_set (G_OBJECT(streamer->buffer), "temp-template", file_buffer_name, NULL);
321 g_object_set (G_OBJECT(streamer->buffer), "file-buffer-max-size", file_buffer_size, NULL);
328 #define GET_BYTE_FROM_BIT(bit) (bit/8)
329 void __mm_player_streaming_buffering(mm_player_streaming_t* streamer, GstMessage *buffering_msg)
331 GstBufferingMode mode = GST_BUFFERING_STREAM;
332 gint byte_in_rate = 0;
333 gint byte_out_rate = 0;
334 gint64 buffering_left = -1;
335 gdouble buffering_time = DEFAULT_BUFFERING_TIME;
336 gdouble low_percent = 0.0;
337 gdouble high_percent = 0.0;
338 guint high_percent_byte = 0;
339 gint buffer_percent = 0;
340 guint buffer_criteria = 0;
342 return_if_fail ( streamer );
343 return_if_fail ( buffering_msg );
344 return_if_fail ( GST_IS_MESSAGE ( buffering_msg ) );
345 return_if_fail ( GST_MESSAGE_TYPE ( buffering_msg ) == GST_MESSAGE_BUFFERING );
347 /* update when buffering has started. */
348 if ( !streamer->is_buffering )
350 debug_log ( "buffering has started.\n" );
352 streamer->is_buffering = TRUE;
353 streamer->buffering_percent = -1;
354 streamer->need_update = TRUE;
357 /* update buffer percent */
358 gst_message_parse_buffering ( buffering_msg, &buffer_percent );
360 if ( streamer->buffering_percent < buffer_percent )
362 debug_log ( "buffering %d%%....\n", buffer_percent );
363 streamer->buffering_percent = buffer_percent;
366 if ( streamer->buffering_percent == MAX_BUFFER_PERCENT )
368 debug_log ( "buffering had done.\n" );
369 streamer->is_buffering = FALSE;
372 if (!streamer->need_update)
374 debug_log ( "don't need to update buffering stats during buffering.\n" );
378 /* Note : Parse the buffering message to get the in/out throughput.
379 * avg_in is the network throughput and avg_out is the consumed throughtput by the linkded element.
381 gst_message_parse_buffering_stats ( buffering_msg, &mode, &byte_in_rate, &byte_out_rate, &buffering_left );
383 if (streamer->buffer_max_bitrate > 0)
385 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate);
386 byte_out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate /3);
388 else if (streamer->buffer_avg_bitrate > 0)
390 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3);
391 byte_out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate);
394 debug_log ( "in rate is %d, out rate is %d (bytes/sec).\n", byte_in_rate, byte_out_rate );
396 if ( byte_in_rate > 0 && byte_out_rate > 0)
397 buffering_time = byte_out_rate / byte_in_rate;
398 else if (byte_in_rate <= 0 && byte_out_rate > 0)
399 buffering_time = MAX_BUFFERING_TIME;
401 buffering_time = DEFAULT_BUFFERING_TIME;
403 streaming_set_buffering_time(streamer, buffering_time);
405 /* calculate buffer low/high percent */
406 low_percent = DEFAULT_BUFFER_LOW_PERCENT;
408 if ( buffer_criteria > 0 )
410 high_percent_byte = buffer_criteria * streamer->buffering_time;
411 high_percent = ( (gdouble)high_percent_byte * 100.0 ) / (gdouble)streamer->buffer_size;
415 high_percent_byte = streamer->buffer_high_percent * streamer->buffer_size / 100;
416 high_percent= streamer->buffer_high_percent;
419 if ( streamer->buffer_size < high_percent_byte )
421 debug_log ( "buffer size[%d bytes] is smaller than high threshold[%d bytes]. update it. \n",
422 streamer->buffer_size, high_percent_byte );
424 streaming_set_buffer_size(streamer, high_percent_byte * 1.1);
427 streaming_set_buffer_percent(streamer, low_percent, high_percent);
429 streamer->need_update = FALSE;