X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=plugins%2Felements%2Fgstdownloadbuffer.c;h=36455ac2462634b1d906e8211254c6204125a454;hb=64a1d4ad0bcc79b09ac0d0636927597ed50943c7;hp=9b155fca833413f143cb8cd14583d819f45f8c20;hpb=f28a4cc671f161db2698a7e17a8e7b662dbf6d33;p=platform%2Fupstream%2Fgstreamer.git
diff --git a/plugins/elements/gstdownloadbuffer.c b/plugins/elements/gstdownloadbuffer.c
index 9b155fc..36455ac 100644
--- a/plugins/elements/gstdownloadbuffer.c
+++ b/plugins/elements/gstdownloadbuffer.c
@@ -21,6 +21,7 @@
/**
* SECTION:element-downloadbuffer
+ * @title: downloadbuffer
*
* The downloadbuffer element provides on-disk buffering and caching of, typically,
* a network file. temp-template should be set to a value such as
@@ -30,7 +31,7 @@
* With max-size-bytes and max-size-time you can configure the buffering limits.
* The downloadbuffer element will try to read-ahead these amounts of data. When
* the amount of read-ahead data drops below low-percent of the configured max,
- * the element will start emiting BUFFERING messages until high-percent of max is
+ * the element will start emitting BUFFERING messages until high-percent of max is
* reached again.
*
* The downloadbuffer provides push and pull based scheduling on its source pad
@@ -42,15 +43,12 @@
* When the downloadbuffer has completely downloaded the media, it will
* post an application message named "GstCacheDownloadComplete"
* with the following information:
- *
- *
- *
+ *
+ * *
* G_TYPE_STRING
* "location":
* the location of the completely downloaded file.
- *
- *
- *
+ *
*/
#ifdef HAVE_CONFIG_H
@@ -70,12 +68,14 @@
#include /* lseek, open, close, read */
#undef lseek
#define lseek _lseeki64
-#undef off_t
-#define off_t guint64
#else
#include
#endif
+#ifdef __BIONIC__
+#include
+#endif
+
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
@@ -174,7 +174,7 @@ enum
G_DEFINE_TYPE_WITH_CODE (GstDownloadBuffer, gst_download_buffer,
GST_TYPE_ELEMENT, _do_init);
-static void update_buffering (GstDownloadBuffer * dlbuf);
+static GstMessage *update_buffering (GstDownloadBuffer * dlbuf);
static void gst_download_buffer_finalize (GObject * object);
@@ -225,11 +225,13 @@ gst_download_buffer_class_init (GstDownloadBufferClass * klass)
g_param_spec_uint ("max-size-bytes", "Max. size (kB)",
"Max. amount of data to buffer (bytes, 0=disable)",
0, G_MAXUINT, DEFAULT_MAX_SIZE_BYTES,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
+ G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIME,
g_param_spec_uint64 ("max-size-time", "Max. size (ns)",
"Max. amount of data to buffer (in ns, 0=disable)", 0, G_MAXUINT64,
- DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
+ G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LOW_PERCENT,
g_param_spec_int ("low-percent", "Low percent",
@@ -267,10 +269,8 @@ gst_download_buffer_class_init (GstDownloadBufferClass * klass)
/* set several parent class virtual functions */
gobject_class->finalize = gst_download_buffer_finalize;
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&srctemplate));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&sinktemplate));
+ gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
+ gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
gst_element_class_set_static_metadata (gstelement_class, "DownloadBuffer",
"Generic", "Download Buffer element",
@@ -327,8 +327,6 @@ gst_download_buffer_init (GstDownloadBuffer * dlbuf)
dlbuf->waiting_add = FALSE;
g_cond_init (&dlbuf->item_add);
- dlbuf->buffering_percent = 100;
-
/* tempfile related */
dlbuf->temp_template = NULL;
dlbuf->temp_location = NULL;
@@ -354,6 +352,18 @@ gst_download_buffer_finalize (GObject * object)
}
static void
+reset_positions (GstDownloadBuffer * dlbuf)
+{
+ dlbuf->write_pos = 0;
+ dlbuf->read_pos = 0;
+ dlbuf->filling = TRUE;
+ dlbuf->buffering_percent = 0;
+ dlbuf->is_buffering = TRUE;
+ dlbuf->seeking = FALSE;
+ GST_DOWNLOAD_BUFFER_CLEAR_LEVEL (dlbuf->cur_level);
+}
+
+static void
reset_rate_timer (GstDownloadBuffer * dlbuf)
{
dlbuf->bytes_in = 0;
@@ -380,25 +390,19 @@ reset_rate_timer (GstDownloadBuffer * dlbuf)
#define AVG_OUT(avg,val) ((avg) * 3.0 + (val)) / 4.0
static void
-update_time_level (GstDownloadBuffer * dlbuf)
+update_levels (GstDownloadBuffer * dlbuf, guint bytes)
{
+ dlbuf->cur_level.bytes = bytes;
+
if (dlbuf->byte_in_rate > 0.0) {
dlbuf->cur_level.time =
dlbuf->cur_level.bytes / dlbuf->byte_in_rate * GST_SECOND;
}
+
GST_DEBUG ("levels: bytes %u/%u, time %" GST_TIME_FORMAT "/%" GST_TIME_FORMAT,
dlbuf->cur_level.bytes, dlbuf->max_level.bytes,
GST_TIME_ARGS (dlbuf->cur_level.time),
GST_TIME_ARGS (dlbuf->max_level.time));
- /* update the buffering */
- update_buffering (dlbuf);
-}
-
-static void
-update_levels (GstDownloadBuffer * dlbuf, guint bytes)
-{
- dlbuf->cur_level.bytes = bytes;
- update_time_level (dlbuf);
}
static void
@@ -556,14 +560,15 @@ get_buffering_stats (GstDownloadBuffer * dlbuf, gint percent,
}
}
-static void
+static GstMessage *
update_buffering (GstDownloadBuffer * dlbuf)
{
gint percent;
gboolean post = FALSE;
+ GstMessage *message = NULL;
if (!get_buffering_percent (dlbuf, NULL, &percent))
- return;
+ return NULL;
if (dlbuf->is_buffering) {
post = TRUE;
@@ -587,7 +592,6 @@ update_buffering (GstDownloadBuffer * dlbuf)
}
if (post) {
- GstMessage *message;
GstBufferingMode mode;
gint avg_in, avg_out;
gint64 buffering_left;
@@ -599,9 +603,9 @@ update_buffering (GstDownloadBuffer * dlbuf)
(gint) percent);
gst_message_set_buffering_stats (message, mode,
avg_in, avg_out, buffering_left);
-
- gst_element_post_message (GST_ELEMENT_CAST (dlbuf), message);
}
+
+ return message;
}
static gboolean
@@ -644,6 +648,7 @@ get_seek_threshold (GstDownloadBuffer * dlbuf)
return threshold;
}
+/* called with DOWNLOAD_BUFFER_MUTEX */
static void
gst_download_buffer_update_upstream_size (GstDownloadBuffer * dlbuf)
{
@@ -726,6 +731,7 @@ out_flushing:
}
}
+/* called with DOWNLOAD_BUFFER_MUTEX */
static gboolean
check_upstream_size (GstDownloadBuffer * dlbuf, gsize offset, guint * length)
{
@@ -832,6 +838,7 @@ hit_eos:
out_flushing:
{
GST_DEBUG_OBJECT (dlbuf, "we are flushing");
+ g_clear_error (&error);
gst_buffer_unmap (buf, &info);
if (*buffer == NULL)
gst_buffer_unref (buf);
@@ -861,7 +868,7 @@ gst_download_buffer_open_temp_location_file (GstDownloadBuffer * dlbuf)
GST_DEBUG_OBJECT (dlbuf, "opening temp file %s", dlbuf->temp_template);
- /* If temp_template was set, allocate a filename and open that filen */
+ /* If temp_template was set, allocate a filename and open that file */
/* nothing to do */
if (dlbuf->temp_template == NULL)
@@ -869,7 +876,11 @@ gst_download_buffer_open_temp_location_file (GstDownloadBuffer * dlbuf)
/* make copy of the template, we don't want to change this */
name = g_strdup (dlbuf->temp_template);
+#ifdef __BIONIC__
+ fd = g_mkstemp_full (name, O_RDWR | O_LARGEFILE, S_IRUSR | S_IWUSR);
+#else
fd = g_mkstemp (name);
+#endif
if (fd == -1)
goto mkstemp_failed;
@@ -882,6 +893,7 @@ gst_download_buffer_open_temp_location_file (GstDownloadBuffer * dlbuf)
g_free (dlbuf->temp_location);
dlbuf->temp_location = name;
dlbuf->temp_fd = fd;
+ reset_positions (dlbuf);
GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
@@ -962,7 +974,7 @@ gst_download_buffer_locked_flush (GstDownloadBuffer * dlbuf, gboolean full,
{
if (clear_temp)
gst_download_buffer_flush_temp_file (dlbuf);
- GST_DOWNLOAD_BUFFER_CLEAR_LEVEL (dlbuf->cur_level);
+ reset_positions (dlbuf);
gst_event_replace (&dlbuf->stream_start_event, NULL);
gst_event_replace (&dlbuf->segment_event, NULL);
}
@@ -1038,6 +1050,8 @@ gst_download_buffer_handle_sink_event (GstPad * pad, GstObject * parent,
}
default:
if (GST_EVENT_IS_SERIALIZED (event)) {
+ GstMessage *msg = NULL;
+
/* serialized events go in the buffer */
GST_DOWNLOAD_BUFFER_MUTEX_LOCK_CHECK (dlbuf, dlbuf->sinkresult,
out_flushing);
@@ -1048,6 +1062,8 @@ gst_download_buffer_handle_sink_event (GstPad * pad, GstObject * parent,
* filled and we can read all data from the dlbuf. */
/* update the buffering status */
update_levels (dlbuf, dlbuf->max_level.bytes);
+ /* update the buffering */
+ msg = update_buffering (dlbuf);
/* wakeup the waiter and let it recheck */
GST_DOWNLOAD_BUFFER_SIGNAL_ADD (dlbuf, -1);
break;
@@ -1065,6 +1081,8 @@ gst_download_buffer_handle_sink_event (GstPad * pad, GstObject * parent,
}
gst_event_unref (event);
GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
+ if (msg != NULL)
+ gst_element_post_message (GST_ELEMENT_CAST (dlbuf), msg);
} else {
/* non-serialized events are passed upstream. */
ret = gst_pad_push_event (dlbuf->srcpad, event);
@@ -1114,6 +1132,7 @@ gst_download_buffer_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
guint64 offset;
gsize res, available;
GError *error = NULL;
+ GstMessage *msg = NULL;
dlbuf = GST_DOWNLOAD_BUFFER (parent);
@@ -1195,8 +1214,14 @@ gst_download_buffer_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
update_levels (dlbuf, 0);
}
+ /* update the buffering */
+ msg = update_buffering (dlbuf);
+
GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
+ if (msg != NULL)
+ gst_element_post_message (GST_ELEMENT_CAST (dlbuf), msg);
+
return GST_FLOW_OK;
/* ERRORS */
@@ -1225,6 +1250,7 @@ out_seeking:
}
write_error:
{
+ GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
gst_buffer_unmap (buffer, &info);
gst_buffer_unref (buffer);
GST_ELEMENT_ERROR (dlbuf, RESOURCE, WRITE,
@@ -1238,12 +1264,18 @@ completed:
dlbuf->write_pos = dlbuf->upstream_size;
dlbuf->filling = FALSE;
update_levels (dlbuf, dlbuf->max_level.bytes);
+ msg = update_buffering (dlbuf);
+
gst_element_post_message (GST_ELEMENT_CAST (dlbuf),
gst_message_new_element (GST_OBJECT_CAST (dlbuf),
gst_structure_new ("GstCacheDownloadComplete",
"location", G_TYPE_STRING, dlbuf->temp_location, NULL)));
+
GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
+ if (msg != NULL)
+ gst_element_post_message (GST_ELEMENT_CAST (dlbuf), msg);
+
return GST_FLOW_EOS;
}
}
@@ -1256,6 +1288,7 @@ gst_download_buffer_loop (GstPad * pad)
GstDownloadBuffer *dlbuf;
GstFlowReturn ret;
GstBuffer *buffer = NULL;
+ GstMessage *msg = NULL;
dlbuf = GST_DOWNLOAD_BUFFER (GST_PAD_PARENT (pad));
@@ -1275,9 +1308,15 @@ gst_download_buffer_loop (GstPad * pad)
if (ret != GST_FLOW_OK)
goto out_flushing;
+ /* update the buffering */
+ msg = update_buffering (dlbuf);
+
g_atomic_int_set (&dlbuf->downstream_may_block, 1);
GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
+ if (msg != NULL)
+ gst_element_post_message (GST_ELEMENT_CAST (dlbuf), msg);
+
ret = gst_pad_push (dlbuf->srcpad, buffer);
g_atomic_int_set (&dlbuf->downstream_may_block, 0);
@@ -1305,10 +1344,7 @@ out_flushing:
* file. */
gst_pad_push_event (dlbuf->srcpad, gst_event_new_eos ());
} else if ((ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS)) {
- GST_ELEMENT_ERROR (dlbuf, STREAM, FAILED,
- (_("Internal data flow error.")),
- ("streaming task paused, reason %s (%d)",
- gst_flow_get_name (ret), ret));
+ GST_ELEMENT_FLOW_ERROR (dlbuf, ret);
gst_pad_push_event (dlbuf->srcpad, gst_event_new_eos ());
}
return;
@@ -1397,9 +1433,13 @@ gst_download_buffer_handle_src_query (GstPad * pad, GstObject * parent,
switch (format) {
case GST_FORMAT_BYTES:
peer_pos -= dlbuf->cur_level.bytes;
+ if (peer_pos < 0) /* Clamp result to 0 */
+ peer_pos = 0;
break;
case GST_FORMAT_TIME:
peer_pos -= dlbuf->cur_level.time;
+ if (peer_pos < 0) /* Clamp result to 0 */
+ peer_pos = 0;
break;
default:
GST_WARNING_OBJECT (dlbuf, "dropping query in %s format, don't "
@@ -1447,6 +1487,7 @@ gst_download_buffer_handle_src_query (GstPad * pad, GstObject * parent,
gint64 duration;
gsize offset, range_start, range_stop;
+ GST_DOWNLOAD_BUFFER_MUTEX_LOCK (dlbuf);
write_pos = dlbuf->write_pos;
/* get duration of upstream in bytes */
@@ -1456,49 +1497,35 @@ gst_download_buffer_handle_src_query (GstPad * pad, GstObject * parent,
GST_DEBUG_OBJECT (dlbuf, "percent %d, duration %" G_GINT64_FORMAT
", writing %" G_GINT64_FORMAT, percent, duration, write_pos);
- /* calculate remaining and total download time */
- if (duration > write_pos && avg_in > 0.0)
- estimated_total = ((duration - write_pos) * 1000) / avg_in;
- else
- estimated_total = -1;
-
- GST_DEBUG_OBJECT (dlbuf, "estimated-total %" G_GINT64_FORMAT,
- estimated_total);
-
gst_query_parse_buffering_range (query, &format, NULL, NULL, NULL);
- switch (format) {
- case GST_FORMAT_PERCENT:
- start = 0;
- /* get our available data relative to the duration */
- if (duration != -1)
- stop =
- gst_util_uint64_scale (GST_FORMAT_PERCENT_MAX, write_pos,
- duration);
- else
- stop = -1;
- break;
- case GST_FORMAT_BYTES:
- start = 0;
- stop = write_pos;
- break;
- default:
- start = -1;
- stop = -1;
- break;
- }
-
- gst_query_set_buffering_range (query, format, start, stop,
- estimated_total);
-
/* fill out the buffered ranges */
- offset = 0;
+ start = offset = 0;
+ stop = -1;
+ estimated_total = -1;
while (gst_sparse_file_get_range_after (dlbuf->file, offset,
&range_start, &range_stop)) {
+ gboolean current_range;
+
+ GST_DEBUG_OBJECT (dlbuf,
+ "range starting at %" G_GSIZE_FORMAT " and finishing at %"
+ G_GSIZE_FORMAT, range_start, range_stop);
+
offset = range_stop;
+ /* find the range we are currently downloading, we'll remember it
+ * after we convert to the target format */
+ if (range_start <= write_pos && range_stop >= write_pos) {
+ current_range = TRUE;
+ /* calculate remaining and total download time */
+ if (duration >= range_stop && avg_in > 0.0)
+ estimated_total = ((duration - range_stop) * 1000) / avg_in;
+ } else
+ current_range = FALSE;
+
switch (format) {
case GST_FORMAT_PERCENT:
+ /* get our available data relative to the duration */
if (duration == -1) {
range_start = 0;
range_stop = 0;
@@ -1516,13 +1543,27 @@ gst_download_buffer_handle_src_query (GstPad * pad, GstObject * parent,
range_stop = -1;
break;
}
+
+ if (current_range) {
+ /* we are currently downloading this range */
+ start = range_start;
+ stop = range_stop;
+ }
+ GST_DEBUG_OBJECT (dlbuf,
+ "range to format: %" G_GSIZE_FORMAT " - %" G_GSIZE_FORMAT,
+ range_start, range_stop);
if (range_start == range_stop)
continue;
- GST_DEBUG_OBJECT (dlbuf,
- "range starting at %" G_GSIZE_FORMAT " and finishing at %"
- G_GSIZE_FORMAT, range_start, range_stop);
gst_query_add_buffering_range (query, range_start, range_stop);
}
+
+ GST_DEBUG_OBJECT (dlbuf, "estimated-total %" G_GINT64_FORMAT,
+ estimated_total);
+
+ gst_query_set_buffering_range (query, format, start, stop,
+ estimated_total);
+
+ GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
}
break;
}
@@ -1575,14 +1616,21 @@ gst_download_buffer_get_range (GstPad * pad, GstObject * parent, guint64 offset,
{
GstDownloadBuffer *dlbuf;
GstFlowReturn ret;
+ GstMessage *msg = NULL;
dlbuf = GST_DOWNLOAD_BUFFER_CAST (parent);
GST_DOWNLOAD_BUFFER_MUTEX_LOCK_CHECK (dlbuf, dlbuf->srcresult, out_flushing);
/* FIXME - function will block when the range is not yet available */
ret = gst_download_buffer_read_buffer (dlbuf, offset, length, buffer);
+ /* update the buffering */
+ msg = update_buffering (dlbuf);
+
GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
+ if (msg != NULL)
+ gst_element_post_message (GST_ELEMENT_CAST (dlbuf), msg);
+
return ret;
/* ERRORS */
@@ -1821,6 +1869,7 @@ gst_download_buffer_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstDownloadBuffer *dlbuf = GST_DOWNLOAD_BUFFER (object);
+ GstMessage *msg = NULL;
/* someone could change levels here, and since this
* affects the get/put funcs, we need to lock for safety. */
@@ -1829,11 +1878,11 @@ gst_download_buffer_set_property (GObject * object,
switch (prop_id) {
case PROP_MAX_SIZE_BYTES:
dlbuf->max_level.bytes = g_value_get_uint (value);
- CAPACITY_CHANGE (dlbuf);
+ msg = CAPACITY_CHANGE (dlbuf);
break;
case PROP_MAX_SIZE_TIME:
dlbuf->max_level.time = g_value_get_uint64 (value);
- CAPACITY_CHANGE (dlbuf);
+ msg = CAPACITY_CHANGE (dlbuf);
break;
case PROP_LOW_PERCENT:
dlbuf->low_percent = g_value_get_int (value);
@@ -1853,6 +1902,10 @@ gst_download_buffer_set_property (GObject * object,
}
GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
+
+ if (msg != NULL)
+ gst_element_post_message (GST_ELEMENT_CAST (dlbuf), msg);
+
}
static void