fdsink: make fdsink seekable
authorBenjamin Gaignard <benjamin at gaignard.net>
Thu, 18 Jun 2009 08:55:39 +0000 (10:55 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Thu, 18 Jun 2009 08:55:39 +0000 (10:55 +0200)
Implement the same logic as filesink to implement seeking.

Fixes #578908

plugins/elements/gstfdsink.c

index ace6777..9cd84a3 100644 (file)
@@ -120,6 +120,9 @@ static gboolean gst_fd_sink_start (GstBaseSink * basesink);
 static gboolean gst_fd_sink_stop (GstBaseSink * basesink);
 static gboolean gst_fd_sink_unlock (GstBaseSink * basesink);
 static gboolean gst_fd_sink_unlock_stop (GstBaseSink * basesink);
+static gboolean gst_fd_sink_event (GstBaseSink * sink, GstEvent * event);
+
+static gboolean gst_fd_sink_do_seek (GstFdSink * fdsink, guint64 new_offset);
 
 static void
 gst_fd_sink_base_init (gpointer g_class)
@@ -153,7 +156,7 @@ gst_fd_sink_class_init (GstFdSinkClass * klass)
   gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_fd_sink_stop);
   gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock);
   gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock_stop);
-  gstbasesink_class->event = NULL;
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_fd_sink_event);
 
   g_object_class_install_property (gobject_class, ARG_FD,
       g_param_spec_int ("fd", "fd", "An open file descriptor to write to",
@@ -171,6 +174,7 @@ gst_fd_sink_init (GstFdSink * fdsink, GstFdSinkClass * klass)
   fdsink->fd = 1;
   fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd);
   fdsink->bytes_written = 0;
+  fdsink->current_pos = 0;
 
   GST_BASE_SINK (fdsink)->sync = TRUE;
 }
@@ -200,8 +204,7 @@ gst_fd_sink_query (GstPad * pad, GstQuery * query)
       switch (format) {
         case GST_FORMAT_DEFAULT:
         case GST_FORMAT_BYTES:
-          gst_query_set_position (query, GST_FORMAT_BYTES,
-              fdsink->bytes_written);
+          gst_query_set_position (query, GST_FORMAT_BYTES, fdsink->current_pos);
           return TRUE;
         default:
           return FALSE;
@@ -274,6 +277,7 @@ again:
   size -= written;
   data += written;
   fdsink->bytes_written += written;
+  fdsink->current_pos += written;
 
   GST_DEBUG_OBJECT (fdsink, "wrote %d bytes, %d left", written, size);
 
@@ -374,6 +378,9 @@ gst_fd_sink_start (GstBaseSink * basesink)
   gst_poll_add_fd (fdsink->fdset, &fd);
   gst_poll_fd_ctl_write (fdsink->fdset, &fd, TRUE);
 
+  fdsink->bytes_written = 0;
+  fdsink->current_pos = 0;
+
   return TRUE;
 
   /* ERRORS */
@@ -501,6 +508,85 @@ gst_fd_sink_get_property (GObject * object, guint prop_id, GValue * value,
   }
 }
 
+static gboolean
+gst_fd_sink_do_seek (GstFdSink * fdsink, guint64 new_offset)
+{
+  off_t result;
+
+  result = lseek (fdsink->fd, new_offset, SEEK_SET);
+
+  if (result == -1)
+    goto seek_failed;
+
+  fdsink->current_pos = new_offset;
+
+  GST_DEBUG_OBJECT (fdsink, "File desciptor \"%d\" to seek to position %lld",
+      fdsink->fd, fdsink->current_pos);
+
+  return TRUE;
+
+  /* ERRORS */
+seek_failed:
+  {
+    GST_DEBUG_OBJECT (fdsink,
+        "File desciptor \"%d\" failed to seek to position %lld", fdsink->fd,
+        new_offset);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_fd_sink_event (GstBaseSink * sink, GstEvent * event)
+{
+  GstEventType type;
+  GstFdSink *fdsink;
+
+  fdsink = GST_FD_SINK (sink);
+
+  type = GST_EVENT_TYPE (event);
+
+  switch (type) {
+    case GST_EVENT_NEWSEGMENT:
+    {
+      gint64 start, stop, pos;
+      GstFormat format;
+      gst_event_parse_new_segment (event, NULL, NULL, &format, &start,
+          &stop, &pos);
+
+      if (format == GST_FORMAT_BYTES) {
+        /* only try to seek and fail when we are going to a different
+         * position */
+        if (fdsink->current_pos != start) {
+          /* FIXME, the seek should be performed on the pos field, start/stop are
+           * just boundaries for valid bytes offsets. We should also fill the file
+           * with zeroes if the new position extends the current EOF (sparse streams
+           * and segment accumulation). */
+          if (!gst_fd_sink_do_seek (fdsink, (guint64) start))
+            goto seek_failed;
+        }
+      } else {
+        GST_DEBUG_OBJECT (fdsink,
+            "Ignored NEWSEGMENT event of format %u (%s)", (guint) format,
+            gst_format_get_name (format));
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+
+seek_failed:
+  {
+    GST_ELEMENT_ERROR (fdsink, RESOURCE, SEEK,
+        (_("Error while seeking in file \"%d\"."), fdsink->fd),
+        GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+
+}
+
 /*** GSTURIHANDLER INTERFACE *************************************************/
 
 static GstURIType