gst_plugins_base/gst/playback/gstqueue2.c
changeset 16 8e837d1bf446
parent 0 0e761a78d257
child 30 7e817e7e631c
--- a/gst_plugins_base/gst/playback/gstqueue2.c	Wed Mar 24 17:58:42 2010 -0500
+++ b/gst_plugins_base/gst/playback/gstqueue2.c	Wed Mar 24 18:04:17 2010 -0500
@@ -27,8 +27,8 @@
  * @short_description: Asynchronous data queue.
  *
  * Data is queued until one of the limits specified by the
- * #GstQueue:max-size-buffers, #GstQueue:max-size-bytes and/or
- * #GstQueue:max-size-time properties has been reached. Any attempt to push
+ * #GstQueue2:max-size-buffers, #GstQueue2:max-size-bytes and/or
+ * #GstQueue2:max-size-time properties has been reached. Any attempt to push
  * more buffers into the queue will block the pushing thread until more space
  * becomes available.
  *
@@ -36,16 +36,22 @@
  * processing on sink and source pad.
  *
  * You can query how many buffers are queued by reading the
- * #GstQueue:current-level-buffers property.
+ * #GstQueue2:current-level-buffers property.
  *
  * The default queue size limits are 100 buffers, 2MB of data, or
  * two seconds worth of data, whichever is reached first.
  *
- * If you set temp-location, the element will buffer data on the file
- * specified by it. By using this, it will buffer the entire 
- * stream data on the file independently of the queue size limits, they
- * will only be used for buffering statistics.
+ * If you set temp-tmpl to a value such as /tmp/gstreamer-XXXXXX, the element
+ * will allocate a random free filename and buffer data in the file.
+ * By using this, it will buffer the entire stream data on the file independently
+ * of the queue size limits, they will only be used for buffering statistics.
  *
+ * Since 0.10.24, setting the temp-location property with a filename is deprecated
+ * because it's impossible to securely open a temporary file in this way. The
+ * property will still be used to notify the application of the allocated
+ * filename, though.
+ *
+ * Last reviewed on 2009-07-10 (0.10.24)
  */
 
 #ifdef HAVE_CONFIG_H
@@ -57,9 +63,16 @@
 #include <gst/gst.h>
 #include <gst/gst-i18n-plugin.h>
 
-#ifdef __SYMBIAN32__
-#include <glib_global.h>
+#ifdef G_OS_WIN32
+#include <io.h>                 /* lseek, open, close, read */
+#undef lseek
+#define lseek _lseeki64
+#undef off_t
+#define off_t guint64
+#else
+#include <unistd.h>
 #endif
+
 static const GstElementDetails gst_queue_details = GST_ELEMENT_DETAILS ("Queue",
     "Generic",
     "Simple data queue",
@@ -96,7 +109,7 @@
 
 /* other defines */
 #define DEFAULT_BUFFER_SIZE 4096
-#define QUEUE_IS_USING_TEMP_FILE(queue) (queue->temp_location != NULL)
+#define QUEUE_IS_USING_TEMP_FILE(queue) ((queue)->temp_location_set || (queue)->temp_template != NULL)
 
 enum
 {
@@ -111,6 +124,7 @@
   PROP_USE_RATE_ESTIMATE,
   PROP_LOW_PERCENT,
   PROP_HIGH_PERCENT,
+  PROP_TEMP_TEMPLATE,
   PROP_TEMP_LOCATION
 };
 
@@ -199,10 +213,13 @@
   GCond *item_del;              /* signals space now available for writing */
 
   /* temp location stuff */
+  gchar *temp_template;
+  gboolean temp_location_set;
   gchar *temp_location;
   FILE *temp_file;
   guint64 writing_pos;
   guint64 reading_pos;
+  guint64 max_reading_pos;
   /* we need this to send the first new segment event of the stream
    * because we can't save it on the file */
   gboolean segment_event_received;
@@ -228,7 +245,7 @@
                       queue->cur_level.time, \
                       queue->max_level.time, \
                       (guint64) (QUEUE_IS_USING_TEMP_FILE(queue) ? \
-                        queue->writing_pos - queue->reading_pos : \
+                        queue->writing_pos - queue->max_reading_pos : \
                         queue->queue->length))
 
 #define GST_QUEUE_MUTEX_LOCK(q) G_STMT_START {                          \
@@ -367,50 +384,60 @@
   g_object_class_install_property (gobject_class, PROP_CUR_LEVEL_BYTES,
       g_param_spec_uint ("current-level-bytes", "Current level (kB)",
           "Current amount of data in the queue (bytes)",
-          0, G_MAXUINT, 0, G_PARAM_READABLE));
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_CUR_LEVEL_BUFFERS,
       g_param_spec_uint ("current-level-buffers", "Current level (buffers)",
           "Current number of buffers in the queue",
-          0, G_MAXUINT, 0, G_PARAM_READABLE));
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_CUR_LEVEL_TIME,
       g_param_spec_uint64 ("current-level-time", "Current level (ns)",
           "Current amount of data in the queue (in ns)",
-          0, G_MAXUINT64, 0, G_PARAM_READABLE));
+          0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (gobject_class, PROP_MAX_SIZE_BYTES,
       g_param_spec_uint ("max-size-bytes", "Max. size (kB)",
           "Max. amount of data in the queue (bytes, 0=disable)",
-          0, G_MAXUINT, DEFAULT_MAX_SIZE_BYTES, G_PARAM_READWRITE));
+          0, G_MAXUINT, DEFAULT_MAX_SIZE_BYTES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_MAX_SIZE_BUFFERS,
       g_param_spec_uint ("max-size-buffers", "Max. size (buffers)",
-          "Max. number of buffers in the queue (0=disable)",
-          0, G_MAXUINT, DEFAULT_MAX_SIZE_BUFFERS, G_PARAM_READWRITE));
+          "Max. number of buffers in the queue (0=disable)", 0, G_MAXUINT,
+          DEFAULT_MAX_SIZE_BUFFERS,
+          G_PARAM_READWRITE | 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 in the queue (in ns, 0=disable)",
-          0, G_MAXUINT64, DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE));
+          "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64,
+          DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (gobject_class, PROP_USE_BUFFERING,
       g_param_spec_boolean ("use-buffering", "Use buffering",
           "Emit GST_MESSAGE_BUFFERING based on low-/high-percent thresholds",
-          DEFAULT_USE_BUFFERING, G_PARAM_READWRITE));
+          DEFAULT_USE_BUFFERING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_USE_RATE_ESTIMATE,
       g_param_spec_boolean ("use-rate-estimate", "Use Rate Estimate",
           "Estimate the bitrate of the stream to calculate time level",
-          DEFAULT_USE_RATE_ESTIMATE, G_PARAM_READWRITE));
+          DEFAULT_USE_RATE_ESTIMATE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_LOW_PERCENT,
       g_param_spec_int ("low-percent", "Low percent",
-          "Low threshold for buffering to start",
-          0, 100, DEFAULT_LOW_PERCENT, G_PARAM_READWRITE));
+          "Low threshold for buffering to start", 0, 100, DEFAULT_LOW_PERCENT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_HIGH_PERCENT,
       g_param_spec_int ("high-percent", "High percent",
-          "High threshold for buffering to finish",
-          0, 100, DEFAULT_HIGH_PERCENT, G_PARAM_READWRITE));
+          "High threshold for buffering to finish", 0, 100,
+          DEFAULT_HIGH_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TEMP_TEMPLATE,
+      g_param_spec_string ("temp-template", "Temporary File Template",
+          "File template to store temporary files in, should contain directory "
+          "and XXXXXX. (NULL == disabled)",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (gobject_class, PROP_TEMP_LOCATION,
       g_param_spec_string ("temp-location", "Temporary File Location",
-          "Location of a temporary file to store data in",
-          NULL, G_PARAM_READWRITE));
+          "Location to store temporary files in (Deprecated: Only read this "
+          "property, use temp-tmpl to configure the name template)",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&srctemplate));
@@ -487,8 +514,9 @@
   queue->queue = g_queue_new ();
 
   /* tempfile related */
+  queue->temp_template = NULL;
   queue->temp_location = NULL;
-  queue->temp_file = NULL;
+  queue->temp_location_set = FALSE;
 
   GST_DEBUG_OBJECT (queue,
       "initialized queue's not_empty & not_full conditions");
@@ -516,8 +544,8 @@
   g_timer_destroy (queue->out_timer);
 
   /* temp_file path cleanup  */
-  if (queue->temp_location != NULL)
-    g_free (queue->temp_location);
+  g_free (queue->temp_template);
+  g_free (queue->temp_location);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -689,15 +717,27 @@
     }
   }
   if (post) {
+    GstMessage *message;
+    GstBufferingMode mode;
+
     /* scale to high percent so that it becomes the 100% mark */
     percent = percent * 100 / queue->high_percent;
     /* clip */
     if (percent > 100)
       percent = 100;
 
+    if (QUEUE_IS_USING_TEMP_FILE (queue))
+      mode = GST_BUFFERING_DOWNLOAD;
+    else
+      mode = GST_BUFFERING_STREAM;
+
     GST_DEBUG_OBJECT (queue, "buffering %d percent", percent);
-    gst_element_post_message (GST_ELEMENT_CAST (queue),
-        gst_message_new_buffering (GST_OBJECT_CAST (queue), percent));
+    message = gst_message_new_buffering (GST_OBJECT_CAST (queue), percent);
+    gst_message_set_buffering_stats (message, mode,
+        queue->byte_in_rate, queue->byte_out_rate, -1);
+
+    gst_element_post_message (GST_ELEMENT_CAST (queue), message);
+
   } else {
     GST_DEBUG_OBJECT (queue, "filled %d percent", percent);
   }
@@ -800,6 +840,10 @@
     queue->last_out_elapsed = elapsed;
     queue->bytes_out = 0;
   }
+  if (queue->byte_in_rate > 0.0) {
+    queue->cur_level.rate_time =
+        queue->cur_level.bytes / queue->byte_in_rate * GST_SECOND;
+  }
   GST_DEBUG_OBJECT (queue, "rates: out %f, time %" GST_TIME_FORMAT,
       queue->byte_out_rate, GST_TIME_ARGS (queue->cur_level.rate_time));
 }
@@ -811,7 +855,13 @@
   guint8 *data;
   int ret;
 
+#ifdef HAVE_FSEEKO
+  fseeko (queue->temp_file, (off_t) queue->writing_pos, SEEK_SET);
+#elif defined (G_OS_UNIX) || defined (G_OS_WIN32)
+  lseek (fileno (queue->temp_file), (off_t) queue->writing_pos, SEEK_SET);
+#else
   fseek (queue->temp_file, queue->writing_pos, SEEK_SET);
+#endif
 
   data = GST_BUFFER_DATA (buffer);
   size = GST_BUFFER_SIZE (buffer);
@@ -822,6 +872,11 @@
     GST_ERROR_OBJECT (queue, "fwrite returned error");
   }
   queue->writing_pos += size;
+
+  if (queue->writing_pos > queue->max_reading_pos)
+    queue->cur_level.bytes = queue->writing_pos - queue->max_reading_pos;
+  else
+    queue->cur_level.bytes = 0;
 }
 
 /* see if there is enough data in the file to read a full buffer */
@@ -856,7 +911,7 @@
 #ifdef HAVE_FSEEKO
   if (fseeko (queue->temp_file, (off_t) offset, SEEK_SET) != 0)
     goto seek_failed;
-#elif defined (G_OS_UNIX)
+#elif defined (G_OS_UNIX) || defined (G_OS_WIN32)
   if (lseek (fileno (queue->temp_file), (off_t) offset,
           SEEK_SET) == (off_t) - 1)
     goto seek_failed;
@@ -889,6 +944,12 @@
   *buffer = buf;
 
   queue->reading_pos = offset + length;
+  queue->max_reading_pos = MAX (queue->max_reading_pos, queue->reading_pos);
+
+  if (queue->writing_pos > queue->max_reading_pos)
+    queue->cur_level.bytes = queue->writing_pos - queue->max_reading_pos;
+  else
+    queue->cur_level.bytes = 0;
 
   return GST_FLOW_OK;
 
@@ -951,33 +1012,74 @@
 static gboolean
 gst_queue_open_temp_location_file (GstQueue * queue)
 {
-  /* nothing to do */
-  if (queue->temp_location == NULL)
-    goto no_filename;
+  gint fd = -1;
+  gchar *name = NULL;
+
+  GST_DEBUG_OBJECT (queue, "opening temp file %s", queue->temp_template);
+
+  /* we have two cases:
+   * - temp_location was set to something !NULL (Deprecated). in this case we
+   *   open the specified filename.
+   * - temp_template was set, allocate a filename and open that filename
+   */
+  if (!queue->temp_location_set) {
+    /* nothing to do */
+    if (queue->temp_template == NULL)
+      goto no_directory;
 
-  /* open the file for update/writing */
-  queue->temp_file = g_fopen (queue->temp_location, "wb+");
-  /* error creating file */
-  if (queue->temp_file == NULL)
-    goto open_failed;
+    /* make copy of the template, we don't want to change this */
+    name = g_strdup (queue->temp_template);
+    fd = g_mkstemp (name);
+    if (fd == -1)
+      goto mkstemp_failed;
+
+    /* open the file for update/writing */
+    queue->temp_file = fdopen (fd, "wb+");
+    /* error creating file */
+    if (queue->temp_file == NULL)
+      goto open_failed;
+
+    g_free (queue->temp_location);
+    queue->temp_location = name;
+
+    g_object_notify (G_OBJECT (queue), "temp-location");
+  } else {
+    /* open the file for update/writing, this is deprecated but we still need to
+     * support it for API/ABI compatibility */
+    queue->temp_file = g_fopen (queue->temp_location, "wb+");
+    /* error creating file */
+    if (queue->temp_file == NULL)
+      goto open_failed;
+  }
 
   queue->writing_pos = 0;
   queue->reading_pos = 0;
+  queue->max_reading_pos = 0;
 
   return TRUE;
 
   /* ERRORS */
-no_filename:
+no_directory:
   {
     GST_ELEMENT_ERROR (queue, RESOURCE, NOT_FOUND,
-        (_("No file name specified.")), (NULL));
+        (_("No Temp directory specified.")), (NULL));
+    return FALSE;
+  }
+mkstemp_failed:
+  {
+    GST_ELEMENT_ERROR (queue, RESOURCE, OPEN_READ,
+        (_("Could not create temp file \"%s\"."), queue->temp_template),
+        GST_ERROR_SYSTEM);
+    g_free (name);
     return FALSE;
   }
 open_failed:
   {
     GST_ELEMENT_ERROR (queue, RESOURCE, OPEN_READ,
-        (_("Could not open file \"%s\" for reading."), queue->temp_location),
-        GST_ERROR_SYSTEM);
+        (_("Could not open file \"%s\" for reading."), name), GST_ERROR_SYSTEM);
+    g_free (name);
+    if (fd != -1)
+      close (fd);
     return FALSE;
   }
 }
@@ -989,6 +1091,8 @@
   if (queue->temp_file == NULL)
     return;
 
+  GST_DEBUG_OBJECT (queue, "closing temp file");
+
   /* we don't remove the file so that the application can use it as a cache
    * later on */
   fflush (queue->temp_file);
@@ -998,11 +1102,25 @@
 }
 
 static void
+gst_queue_flush_temp_file (GstQueue * queue)
+{
+  if (queue->temp_file == NULL)
+    return;
+
+  GST_DEBUG_OBJECT (queue, "flushing temp file");
+
+  queue->temp_file = g_freopen (queue->temp_location, "wb+", queue->temp_file);
+
+  queue->writing_pos = 0;
+  queue->reading_pos = 0;
+  queue->max_reading_pos = 0;
+}
+
+static void
 gst_queue_locked_flush (GstQueue * queue)
 {
   if (QUEUE_IS_USING_TEMP_FILE (queue)) {
-    gst_queue_close_temp_location_file (queue);
-    gst_queue_open_temp_location_file (queue);
+    gst_queue_flush_temp_file (queue);
   } else {
     while (!g_queue_is_empty (queue->queue)) {
       GstMiniObject *data = g_queue_pop_head (queue->queue);
@@ -1039,6 +1157,7 @@
     queue->cur_level.buffers++;
     queue->cur_level.bytes += size;
     queue->bytes_in += size;
+
     /* apply new buffer to segment stats */
     apply_buffer (queue, buffer, &queue->sink_segment);
     /* update the byterate stats */
@@ -1068,7 +1187,10 @@
             goto unexpected_event;
 
           queue->segment_event_received = TRUE;
+          if (queue->starting_segment != NULL)
+            gst_event_unref (queue->starting_segment);
           queue->starting_segment = event;
+          item = NULL;
         }
         /* a new segment allows us to accept more buffers if we got UNEXPECTED
          * from downstream */
@@ -1092,6 +1214,9 @@
 
     if (!QUEUE_IS_USING_TEMP_FILE (queue))
       g_queue_push_tail (queue->queue, item);
+    else
+      gst_mini_object_unref (GST_MINI_OBJECT_CAST (item));
+
     GST_QUEUE_SIGNAL_ADD (queue);
   }
 
@@ -1266,7 +1391,7 @@
     return FALSE;
 
   if (QUEUE_IS_USING_TEMP_FILE (queue)) {
-    return queue->writing_pos == queue->reading_pos;
+    return queue->writing_pos == queue->max_reading_pos;
   } else {
     if (queue->queue->length == 0)
       return TRUE;
@@ -1288,6 +1413,10 @@
   if (QUEUE_IS_USING_TEMP_FILE (queue))
     return FALSE;
 
+  /* we are never filled when we have no buffers at all */
+  if (queue->cur_level.buffers == 0)
+    return FALSE;
+
 #define CHECK_FILLED(format) ((queue->max_level.format) > 0 && \
 		(queue->cur_level.format) >= (queue->max_level.format))
 
@@ -1548,8 +1677,14 @@
       event, GST_EVENT_TYPE_NAME (event));
 #endif
 
-  /* just forward upstream */
-  res = gst_pad_push_event (queue->sinkpad, event);
+  if (!QUEUE_IS_USING_TEMP_FILE (queue)) {
+    /* just forward upstream */
+    res = gst_pad_push_event (queue->sinkpad, event);
+  } else {
+    /* when using a temp file, we unblock the pending read */
+    res = TRUE;
+    gst_event_unref (event);
+  }
 
   return res;
 }
@@ -1605,15 +1740,7 @@
     }
     case GST_QUERY_DURATION:
     {
-      GST_DEBUG_OBJECT (queue, "waiting for preroll in duration query");
-
-      GST_QUEUE_MUTEX_LOCK (queue);
-      /* we have to wait until the upstream element is at least paused, which
-       * happened when we received a first item. */
-      while (gst_queue_is_empty (queue)) {
-        GST_QUEUE_WAIT_ADD_CHECK (queue, flushing);
-      }
-      GST_QUEUE_MUTEX_UNLOCK (queue);
+      GST_DEBUG_OBJECT (queue, "doing peer query");
 
       if (!gst_queue_peer_query (queue, queue->sinkpad, query))
         goto peer_failed;
@@ -1621,6 +1748,59 @@
       GST_DEBUG_OBJECT (queue, "peer query success");
       break;
     }
+    case GST_QUERY_BUFFERING:
+    {
+      GstFormat format;
+
+      GST_DEBUG_OBJECT (queue, "query buffering");
+
+      if (!QUEUE_IS_USING_TEMP_FILE (queue)) {
+        /* no temp file, just forward to the peer */
+        if (!gst_queue_peer_query (queue, queue->sinkpad, query))
+          goto peer_failed;
+        GST_DEBUG_OBJECT (queue, "buffering forwarded to peer");
+      } else {
+        gint64 start, stop;
+
+        gst_query_parse_buffering_range (query, &format, NULL, NULL, NULL);
+
+        switch (format) {
+          case GST_FORMAT_PERCENT:
+          {
+            gint64 duration;
+            GstFormat peer_fmt;
+
+            peer_fmt = GST_FORMAT_BYTES;
+
+            if (!gst_pad_query_peer_duration (queue->sinkpad, &peer_fmt,
+                    &duration))
+              goto peer_failed;
+
+            GST_DEBUG_OBJECT (queue, "duration %" G_GINT64_FORMAT ", writing %"
+                G_GINT64_FORMAT, duration, queue->writing_pos);
+
+            start = 0;
+            /* get our available data relative to the duration */
+            if (duration != -1)
+              stop = GST_FORMAT_PERCENT_MAX * queue->writing_pos / duration;
+            else
+              stop = -1;
+            break;
+          }
+          case GST_FORMAT_BYTES:
+            start = 0;
+            stop = queue->writing_pos;
+            break;
+          default:
+            start = -1;
+            stop = -1;
+            break;
+        }
+        gst_query_set_buffering_percent (query, queue->is_buffering, 100);
+        gst_query_set_buffering_range (query, format, start, stop, -1);
+      }
+      break;
+    }
     default:
       /* peer handled other queries */
       if (!gst_queue_peer_query (queue, queue->sinkpad, query))
@@ -1636,12 +1816,6 @@
     GST_DEBUG_OBJECT (queue, "failed peer query");
     return FALSE;
   }
-flushing:
-  {
-    GST_DEBUG_OBJECT (queue, "flushing while waiting for query");
-    GST_QUEUE_MUTEX_UNLOCK (queue);
-    return FALSE;
-  }
 }
 
 static GstFlowReturn
@@ -1681,8 +1855,10 @@
   gboolean ret;
 
   queue = GST_QUEUE (gst_pad_get_parent (pad));
+
   /* we can operate in pull mode when we are using a tempfile */
   ret = QUEUE_IS_USING_TEMP_FILE (queue);
+
   gst_object_unref (GST_OBJECT (queue));
 
   return ret;
@@ -1856,8 +2032,8 @@
 #define QUEUE_THRESHOLD_CHANGE(q)\
   g_cond_signal (queue->item_add);
 
-static gboolean
-gst_queue_set_temp_location (GstQueue * queue, const gchar * location)
+static void
+gst_queue_set_temp_template (GstQueue * queue, const gchar * template)
 {
   GstState state;
 
@@ -1869,19 +2045,16 @@
   GST_OBJECT_UNLOCK (queue);
 
   /* set new location */
-  g_free (queue->temp_location);
-  queue->temp_location = g_strdup (location);
+  g_free (queue->temp_template);
+  queue->temp_template = g_strdup (template);
 
-  g_object_notify (G_OBJECT (queue), "temp-location");
-
-  return TRUE;
+  return;
 
 /* ERROR */
 wrong_state:
   {
-    GST_DEBUG_OBJECT (queue, "setting temp-location in wrong state");
+    GST_WARNING_OBJECT (queue, "setting temp-template property in wrong state");
     GST_OBJECT_UNLOCK (queue);
-    return FALSE;
   }
 }
 
@@ -1923,8 +2096,15 @@
     case PROP_HIGH_PERCENT:
       queue->high_percent = g_value_get_int (value);
       break;
+    case PROP_TEMP_TEMPLATE:
+      gst_queue_set_temp_template (queue, g_value_get_string (value));
+      break;
     case PROP_TEMP_LOCATION:
-      gst_queue_set_temp_location (queue, g_value_dup_string (value));
+      g_free (queue->temp_location);
+      queue->temp_location = g_value_dup_string (value);
+      /* you can set the property back to NULL to make it use the temp-tmpl
+       * property. */
+      queue->temp_location_set = queue->temp_location != NULL;
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1973,6 +2153,9 @@
     case PROP_HIGH_PERCENT:
       g_value_set_int (value, queue->high_percent);
       break;
+    case PROP_TEMP_TEMPLATE:
+      g_value_set_string (value, queue->temp_template);
+      break;
     case PROP_TEMP_LOCATION:
       g_value_set_string (value, queue->temp_location);
       break;
@@ -1995,6 +2178,7 @@
   GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
       LOCALEDIR);
   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 #endif /* ENABLE_NLS */
 
   return gst_element_register (plugin, "queue2", GST_RANK_NONE, GST_TYPE_QUEUE);