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