4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
24 #include "mm_player_utils.h"
26 #include "mm_player_streaming.h"
28 static void streaming_set_buffer_size(mm_player_streaming_t* streamer, guint buffer_size);
29 static void streaming_set_buffer_percent(mm_player_streaming_t* streamer, gdouble low_percent, gdouble high_percent);
30 static void streaming_set_buffer_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size);
31 static void streaming_set_buffering_time(mm_player_streaming_t* streamer, gdouble buffering_time);
34 mm_player_streaming_t *
35 __mm_player_streaming_create ()
37 mm_player_streaming_t *streamer = NULL;
41 streamer = (mm_player_streaming_t *) malloc (sizeof (mm_player_streaming_t));
44 debug_error ("fail to create streaming player handle..\n");
53 void __mm_player_streaming_initialize (mm_player_streaming_t* streamer)
57 streamer->buffer = NULL;
58 streamer->buffer_size = DEFAULT_BUFFER_SIZE;
59 streamer->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
60 streamer->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
61 streamer->buffer_avg_bitrate = 0;
62 streamer->buffer_max_bitrate = 0;
63 streamer->need_update = FALSE;
65 streamer->is_buffering = FALSE;
66 streamer->buffering_percent = -1;
67 streamer->buffering_time = DEFAULT_BUFFERING_TIME;
74 void __mm_player_streaming_deinitialize (mm_player_streaming_t* streamer)
78 return_if_fail(streamer);
80 streamer->buffer_size = DEFAULT_BUFFER_SIZE;
81 streamer->buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
82 streamer->buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
83 streamer->buffer_avg_bitrate = 0;
84 streamer->buffer_max_bitrate = 0;
85 streamer->need_update = FALSE;
87 streamer->is_buffering = FALSE;
88 streamer->buffering_percent = -1;
89 streamer->buffering_time = DEFAULT_BUFFERING_TIME;
97 void __mm_player_streaming_destroy (mm_player_streaming_t* streamer)
113 void __mm_player_streaming_set_buffer(mm_player_streaming_t* streamer, GstElement * buffer,
114 gboolean use_buffering, guint buffer_size, gdouble low_percent, gdouble high_percent, gdouble buffering_time,
115 gboolean use_file, gchar * file_path, guint64 content_size)
119 return_if_fail(streamer);
123 streamer->buffer = buffer;
125 debug_log("buffer element is %s.", GST_ELEMENT_NAME(buffer));
127 g_object_set ( G_OBJECT (streamer->buffer), "use-buffering", use_buffering, NULL );
130 streaming_set_buffer_size(streamer, buffer_size);
131 streaming_set_buffer_percent(streamer, low_percent, high_percent);
132 streaming_set_buffer_type (streamer, use_file, file_path, content_size);
133 streaming_set_buffering_time(streamer, buffering_time);
141 void __mm_player_streaming_set_content_bitrate(mm_player_streaming_t* streamer, guint max_bitrate, guint avg_bitrate)
145 return_if_fail(streamer);
147 /* Note : Update buffering criterion bytes
148 * 1. maximum bitrate is considered first.
149 * 2. average bitrage * 3 is next.
150 * 3. if there are no updated bitrate, use default buffering limit.
152 if (max_bitrate > 0 && streamer->buffer_max_bitrate != max_bitrate)
154 debug_log("set maximum bitrate(%dbps).\n", max_bitrate);
155 streamer->buffer_max_bitrate = max_bitrate;
157 streamer->need_update = TRUE;
160 if (avg_bitrate > 0 && streamer->buffer_avg_bitrate != avg_bitrate)
162 debug_log("set averate bitrate(%dbps).\n", avg_bitrate);
163 streamer->buffer_avg_bitrate = avg_bitrate;
165 streamer->need_update = TRUE;
174 streaming_set_buffer_size(mm_player_streaming_t* streamer, guint buffer_size)
178 return_if_fail(streamer);
179 return_if_fail(buffer_size>0);
181 debug_log("set buffer size to %d.", buffer_size);
183 streamer->buffer_size = buffer_size;
185 if (streamer->buffer)
186 g_object_set (G_OBJECT(streamer->buffer), "max-size-bytes", buffer_size, NULL);
194 streaming_set_buffer_percent(mm_player_streaming_t* streamer, gdouble low_percent, gdouble high_percent)
196 gdouble buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
197 gdouble buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
201 return_if_fail(streamer);
203 if (low_percent <= MIN_BUFFER_PERCENT || low_percent >= MAX_BUFFER_PERCENT)
205 debug_warning("buffer low percent is out of range. use defaut value.");
206 buffer_low_percent = DEFAULT_BUFFER_LOW_PERCENT;
210 buffer_low_percent = low_percent;
213 if (high_percent <= MIN_BUFFER_PERCENT || high_percent >= MAX_BUFFER_PERCENT)
215 debug_warning("buffer high percent is out of range. use defaut value.");
216 buffer_high_percent = DEFAULT_BUFFER_HIGH_PERCENT;
220 buffer_high_percent = high_percent;
223 if (buffer_high_percent <= buffer_low_percent)
224 buffer_high_percent = buffer_low_percent + 1.0;
226 debug_log("set buffer percent to %2.3f ~ %2.3f.", streamer->buffer_low_percent, streamer->buffer_high_percent);
228 if (streamer->buffer)
230 if ( streamer->buffer_low_percent != buffer_low_percent )
231 g_object_set (G_OBJECT(streamer->buffer), "low-percent", streamer->buffer_low_percent, NULL);
233 if ( streamer->buffer_high_percent != buffer_high_percent )
234 g_object_set (G_OBJECT(streamer->buffer), "high-percent", streamer->buffer_high_percent, NULL);
237 streamer->buffer_low_percent = buffer_low_percent;
238 streamer->buffer_high_percent = buffer_high_percent;
246 streaming_set_buffering_time(mm_player_streaming_t* streamer, gdouble buffering_time)
248 gdouble buffer_buffering_time = DEFAULT_BUFFERING_TIME;
252 return_if_fail(streamer);
254 if (buffering_time < MIN_BUFFERING_TIME)
255 buffer_buffering_time = MIN_BUFFERING_TIME;
256 else if (buffering_time > MAX_BUFFERING_TIME)
257 buffer_buffering_time = MAX_BUFFERING_TIME;
259 buffer_buffering_time = buffering_time;
261 if (streamer->buffering_time != buffer_buffering_time)
263 debug_log("set buffer buffering time from %2.1f to %2.1f.", streamer->buffering_time, buffer_buffering_time);
265 streamer->buffering_time = buffer_buffering_time;
274 streaming_set_buffer_type (mm_player_streaming_t* streamer, gboolean use_file, gchar * file_path, guint64 content_size)
276 guint64 storage_available_size = 0L; //bytes
277 guint64 file_buffer_size = 0L; //bytes
278 gchar file_buffer_name[MAX_FILE_BUFFER_NAME_LEN] = {0};
279 struct statfs buf = {0};
283 return_if_fail(streamer && streamer->buffer);
287 debug_log("use memory for buffering. streaming is played on push-based. \n"
288 "buffering position would not be updated.\n"
289 "buffered data would be flushed after played.\n"
290 "seeking and getting duration could be failed due to file format.");
294 debug_log("use file for buffering. streaming is played on pull-based. \n");
296 if (!file_path || strlen(file_path) <= 0)
297 file_path = g_strdup(DEFAULT_FILE_BUFFER_PATH);
299 sprintf( file_buffer_name, "%s/XXXXXX", file_path );
300 debug_log("the buffering file name is %s.\n", file_buffer_name);
302 if (statfs((const char *)file_path, &buf) < 0)
304 debug_warning ("fail to get availabe storage capacity. just use file buffer.\n");
305 file_buffer_size = 0L;
309 storage_available_size = (guint64)buf.f_bavail * (guint64)buf.f_bsize; //bytes
311 debug_log ("the number of available blocks : %"G_GUINT64_FORMAT", the block size is %"G_GUINT64_FORMAT".\n",
312 (guint64)buf.f_bavail, (guint64)buf.f_bsize);
313 debug_log ("calculated availabe storage size is %"G_GUINT64_FORMAT" Bytes.\n", storage_available_size);
315 if (content_size <= 0 || content_size >= storage_available_size)
316 file_buffer_size = storage_available_size;
318 file_buffer_size = 0L;
321 if (file_buffer_size>0)
322 debug_log("use file ring buffer for buffering.");
324 g_object_set (G_OBJECT(streamer->buffer), "temp-template", file_buffer_name, NULL);
325 g_object_set (G_OBJECT(streamer->buffer), "file-buffer-max-size", file_buffer_size, NULL);
332 #define GET_BYTE_FROM_BIT(bit) (bit/8)
333 void __mm_player_streaming_buffering(mm_player_streaming_t* streamer, GstMessage *buffering_msg)
335 GstBufferingMode mode = GST_BUFFERING_STREAM;
336 gint byte_in_rate = 0;
337 gint byte_out_rate = 0;
338 gint64 buffering_left = -1;
339 gdouble buffering_time = DEFAULT_BUFFERING_TIME;
340 gdouble low_percent = 0.0;
341 gdouble high_percent = 0.0;
342 guint high_percent_byte = 0;
343 gint buffer_percent = 0;
344 guint buffer_criteria = 0;
346 return_if_fail ( streamer );
347 return_if_fail ( buffering_msg );
348 return_if_fail ( GST_IS_MESSAGE ( buffering_msg ) );
349 return_if_fail ( GST_MESSAGE_TYPE ( buffering_msg ) == GST_MESSAGE_BUFFERING );
351 /* update when buffering has started. */
352 if ( !streamer->is_buffering )
354 debug_log ( "buffering has started.\n" );
356 streamer->is_buffering = TRUE;
357 streamer->buffering_percent = -1;
358 streamer->need_update = TRUE;
361 /* update buffer percent */
362 gst_message_parse_buffering ( buffering_msg, &buffer_percent );
364 if ( streamer->buffering_percent < buffer_percent )
366 debug_log ( "buffering %d%%....\n", buffer_percent );
367 streamer->buffering_percent = buffer_percent;
370 if ( streamer->buffering_percent == MAX_BUFFER_PERCENT )
372 debug_log ( "buffering had done.\n" );
373 streamer->is_buffering = FALSE;
376 if (!streamer->need_update)
378 debug_log ( "don't need to update buffering stats during buffering.\n" );
382 /* Note : Parse the buffering message to get the in/out throughput.
383 * avg_in is the network throughput and avg_out is the consumed throughtput by the linkded element.
385 gst_message_parse_buffering_stats ( buffering_msg, &mode, &byte_in_rate, &byte_out_rate, &buffering_left );
387 if (streamer->buffer_max_bitrate > 0)
389 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate);
390 byte_out_rate = GET_BYTE_FROM_BIT(streamer->buffer_max_bitrate /3);
392 else if (streamer->buffer_avg_bitrate > 0)
394 buffer_criteria = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate * 3);
395 byte_out_rate = GET_BYTE_FROM_BIT(streamer->buffer_avg_bitrate);
398 debug_log ( "in rate is %d, out rate is %d (bytes/sec).\n", byte_in_rate, byte_out_rate );
400 if ( byte_in_rate > 0 && byte_out_rate > 0)
401 buffering_time = byte_out_rate / byte_in_rate;
402 else if (byte_in_rate <= 0 && byte_out_rate > 0)
403 buffering_time = MAX_BUFFERING_TIME;
405 buffering_time = DEFAULT_BUFFERING_TIME;
407 streaming_set_buffering_time(streamer, buffering_time);
409 /* calculate buffer low/high percent */
410 low_percent = DEFAULT_BUFFER_LOW_PERCENT;
412 if ( buffer_criteria > 0 )
414 high_percent_byte = buffer_criteria * streamer->buffering_time;
415 high_percent = ( (gdouble)high_percent_byte * 100.0 ) / (gdouble)streamer->buffer_size;
419 high_percent_byte = streamer->buffer_high_percent * streamer->buffer_size / 100;
420 high_percent= streamer->buffer_high_percent;
423 if ( streamer->buffer_size < high_percent_byte )
425 debug_log ( "buffer size[%d bytes] is smaller than high threshold[%d bytes]. update it. \n",
426 streamer->buffer_size, high_percent_byte );
428 streaming_set_buffer_size(streamer, high_percent_byte * 1.1);
431 streaming_set_buffer_percent(streamer, low_percent, high_percent);
433 streamer->need_update = FALSE;