this patch implements metadata the wtay way.
authorThomas Vander Stichele <thomas@apestaart.org>
Tue, 29 Oct 2002 02:05:37 +0000 (02:05 +0000)
committerThomas Vander Stichele <thomas@apestaart.org>
Tue, 29 Oct 2002 02:05:37 +0000 (02:05 +0000)
Original commit message from CVS:
this patch implements metadata the wtay way.
some other stuff I still need to clean up to make it work well.
test it with
gst-launch filesrc location=... ! vorbisfile

ext/vorbis/vorbisfile.c

index 4a93615784105e5e6aea5f5a08c284124c69e01b..37fdb79343c37383be348a83c84dbe54de358bde 100644 (file)
@@ -48,6 +48,9 @@ struct _VorbisFile {
 
   gboolean restart;
   gboolean need_discont;
+  gboolean get_metadata;               /* TRUE if we request metadata */
+  gboolean have_metadata;      /* TRUE if we already have this */
+  gboolean have_metadata_technical;    /* TRUE if we already have this */
   gboolean eos;
   gboolean seek_pending;
   gint64 seek_value;
@@ -59,13 +62,30 @@ struct _VorbisFile {
   guint64 total_out;
   guint64 total_bytes;
   guint64 offset;
+
+  int link;                    /* stream id of logical bitstream */
+  int streams;                 /* number of streams in physical bitstream */
+  int version;
+  int channels;
+  long samplerate;
+  long bitrate;
+
+  long bitrate_upper;
+  long bitrate_nominal;
+  long bitrate_lower;
+  /* long bitrate_window;      not set in 1.0 */
+
+  GstCaps *metadata;
 };
 
 struct _VorbisFileClass {
   GstElementClass parent_class;
+
+    /* signals */
+    void (*have_metadata) (GstElement *element);
 };
 
-GType vorbisfile_get_type(void);
+GType vorbisfile_get_type (void);
 
 extern GstPadTemplate *gst_vorbisdec_src_template, *gst_vorbisdec_sink_template;
 
@@ -85,48 +105,70 @@ GstElementDetails vorbisfile_details =
 enum
 {
   /* FILL ME */
+  SIGNAL_HAVE_METADATA,                /* FIXME: maybe separate out in
+                                   - descriptive
+                                   - technical
+                                     - easy
+                                     - hard (expensive)
+                               */
   LAST_SIGNAL
 };
 
 enum
 {
   ARG_0,
-  ARG_COMMENT,
+  ARG_METADATA,
   ARG_VENDOR,
   ARG_VERSION,
   ARG_CHANNELS,
   ARG_RATE,
+  ARG_STREAMS,
+  ARG_LINK,
+  ARG_BITRATE,
   ARG_BITRATE_UPPER,
   ARG_BITRATE_NOMINAL,
   ARG_BITRATE_LOWER,
   ARG_BITRATE_WINDOW,
 };
 
-static void            gst_vorbisfile_class_init       (VorbisFileClass *klass);
-static void            gst_vorbisfile_init             (VorbisFile *vorbisfile);
+static void
+               gst_vorbisfile_class_init       (VorbisFileClass *klass);
+static void    gst_vorbisfile_init             (VorbisFile *vorbisfile);
 
 static GstElementStateReturn
-                       gst_vorbisfile_change_state     (GstElement *element);
-
-static const GstFormat* gst_vorbisfile_get_formats     (GstPad *pad);
-static gboolean        gst_vorbisfile_src_convert      (GstPad *pad, GstFormat src_format, gint64 src_value,
-                                                        GstFormat *dest_format, gint64 *dest_value);
+               gst_vorbisfile_change_state     (GstElement *element);
+
+static const 
+GstFormat*     gst_vorbisfile_get_formats      (GstPad *pad);
+static gboolean gst_vorbisfile_src_convert     (GstPad *pad, 
+                                                GstFormat src_format, 
+                                                gint64 src_value,
+                                                GstFormat *dest_format, 
+                                                gint64 *dest_value);
 static const GstPadQueryType*
-                       gst_vorbisfile_get_query_types  (GstPad *pad);
-
-static gboolean        gst_vorbisfile_src_query        (GstPad *pad, GstPadQueryType type,
-                                                        GstFormat *format, gint64 *value);
-static const GstEventMask*
-                       gst_vorbisfile_get_event_masks  (GstPad *pad);
-static gboolean        gst_vorbisfile_src_event        (GstPad *pad, GstEvent *event);
-
-static void            gst_vorbisfile_get_property     (GObject *object, guint prop_id, 
-                                                        GValue *value, GParamSpec *pspec);
-
-static void            gst_vorbisfile_loop             (GstElement *element);
+               gst_vorbisfile_get_query_types  (GstPad *pad);
+
+static gboolean gst_vorbisfile_src_query       (GstPad *pad, 
+                                                GstPadQueryType type,
+                                                GstFormat *format, 
+                                                gint64 *value);
+static const 
+GstEventMask*  gst_vorbisfile_get_event_masks  (GstPad *pad);
+static gboolean gst_vorbisfile_src_event       (GstPad *pad, GstEvent *event);
+
+static void    gst_vorbisfile_get_property     (GObject *object, 
+                                                guint prop_id, 
+                                                GValue *value, 
+                                                GParamSpec *pspec);
+static void    gst_vorbisfile_set_property     (GObject *object, 
+                                                guint prop_id, 
+                                                const GValue *value, 
+                                                GParamSpec *pspec);
+
+static void    gst_vorbisfile_loop             (GstElement *element);
 
 static GstElementClass *parent_class = NULL;
-/*static guint gst_vorbisfile_signals[LAST_SIGNAL] = { 0 }; */
+static guint gst_vorbisfile_signals[LAST_SIGNAL] = { 0 };
 
 GType
 vorbisfile_get_type (void)
@@ -135,18 +177,14 @@ vorbisfile_get_type (void)
 
   if (!vorbisfile_type) {
     static const GTypeInfo vorbisfile_info = {
-      sizeof (VorbisFileClass), 
-      NULL,
-      NULL,
-      (GClassInitFunc) gst_vorbisfile_class_init,
-      NULL,
-      NULL,
-      sizeof (VorbisFile),
-      0,
+      sizeof (VorbisFileClass), NULL, NULL,
+      (GClassInitFunc) gst_vorbisfile_class_init, NULL, NULL,
+      sizeof (VorbisFile), 0,
       (GInstanceInitFunc) gst_vorbisfile_init,
     };
 
-    vorbisfile_type = g_type_register_static (GST_TYPE_ELEMENT, "VorbisFile", &vorbisfile_info, 0);
+    vorbisfile_type = g_type_register_static (GST_TYPE_ELEMENT, "VorbisFile", 
+                                             &vorbisfile_info, 0);
   }
   return vorbisfile_type;
 }
@@ -162,11 +200,12 @@ gst_vorbisfile_class_init (VorbisFileClass * klass)
 
   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
-  g_object_class_install_property (gobject_class, ARG_COMMENT,
-    g_param_spec_string ("comment", "Comment", "The comment tags for this vorbis stream",
-                         "", G_PARAM_READABLE));
+  g_object_class_install_property (gobject_class, ARG_METADATA,
+    g_param_spec_boxed ("metadata", "Metadata", "Metadata",
+                         GST_TYPE_CAPS, G_PARAM_READABLE));
   g_object_class_install_property (gobject_class, ARG_VENDOR,
-    g_param_spec_string ("vendor", "Vendor", "The vendor for this vorbis stream",
+    g_param_spec_string ("vendor", "Vendor", 
+                        "The vendor for this vorbis stream",
                          "", G_PARAM_READABLE));
   g_object_class_install_property (gobject_class, ARG_VERSION,
     g_param_spec_int ("version", "Version", "The version",
@@ -174,10 +213,22 @@ gst_vorbisfile_class_init (VorbisFileClass * klass)
   g_object_class_install_property (gobject_class, ARG_CHANNELS,
     g_param_spec_int ("channels", "Channels", "The number of channels",
                        0, G_MAXINT, 0, G_PARAM_READABLE));
-  g_object_class_install_property (gobject_class, ARG_RATE,
+  g_object_class_install_property (gobject_class, ARG_STREAMS,
+    g_param_spec_int ("streams", "Streams", 
+                     "Number of logical bitstreams in the physical bitstream",
+                       0, G_MAXINT, 0, G_PARAM_READABLE));
+  g_object_class_install_property (gobject_class, ARG_LINK,
+    g_param_spec_int ("link", "Link", 
+                     "The link id of the current logical bitstream",
+                       -1, G_MAXINT, 0, G_PARAM_READWRITE));
+   g_object_class_install_property (gobject_class, ARG_RATE,
     g_param_spec_int ("rate", "Rate", "The samplerate",
                        0, G_MAXINT, 0, G_PARAM_READABLE));
-  g_object_class_install_property (gobject_class, ARG_BITRATE_UPPER,
+  g_object_class_install_property (gobject_class, ARG_BITRATE,
+    g_param_spec_int ("bitrate", "Bitrate", 
+                     "(average) bitrate in bits per second",
+                       0, G_MAXINT, 0, G_PARAM_READABLE));
+   g_object_class_install_property (gobject_class, ARG_BITRATE_UPPER,
     g_param_spec_int ("bitrate_upper", "bitrate_upper", "bitrate_upper",
                        0, G_MAXINT, 0, G_PARAM_READABLE));
   g_object_class_install_property (gobject_class, ARG_BITRATE_NOMINAL,
@@ -191,6 +242,13 @@ gst_vorbisfile_class_init (VorbisFileClass * klass)
                        0, G_MAXINT, 0, G_PARAM_READABLE));
 
   gobject_class->get_property = gst_vorbisfile_get_property;
+  gobject_class->set_property = gst_vorbisfile_set_property;
+
+  gst_vorbisfile_signals[SIGNAL_HAVE_METADATA] =
+    g_signal_new ("have_metadata", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (VorbisFileClass, have_metadata), 
+                 NULL, NULL, 
+                 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 
   gstelement_class->change_state = gst_vorbisfile_change_state;
 }
@@ -198,17 +256,21 @@ gst_vorbisfile_class_init (VorbisFileClass * klass)
 static void
 gst_vorbisfile_init (VorbisFile * vorbisfile)
 {
-  vorbisfile->sinkpad = gst_pad_new_from_template (gst_vorbisdec_sink_template, "sink");
+  vorbisfile->sinkpad = gst_pad_new_from_template (gst_vorbisdec_sink_template,
+                                                  "sink");
   gst_element_add_pad (GST_ELEMENT (vorbisfile), vorbisfile->sinkpad);
   gst_pad_set_convert_function (vorbisfile->sinkpad, NULL);
 
   gst_element_set_loop_function (GST_ELEMENT (vorbisfile), gst_vorbisfile_loop);
-  vorbisfile->srcpad = gst_pad_new_from_template (gst_vorbisdec_src_template, "src");
+  vorbisfile->srcpad = gst_pad_new_from_template (gst_vorbisdec_src_template, 
+                                                 "src");
   gst_element_add_pad (GST_ELEMENT (vorbisfile), vorbisfile->srcpad);
   gst_pad_set_formats_function (vorbisfile->srcpad, gst_vorbisfile_get_formats);
-  gst_pad_set_query_type_function (vorbisfile->srcpad, gst_vorbisfile_get_query_types);
+  gst_pad_set_query_type_function (vorbisfile->srcpad, 
+                                  gst_vorbisfile_get_query_types);
   gst_pad_set_query_function (vorbisfile->srcpad, gst_vorbisfile_src_query);
-  gst_pad_set_event_mask_function (vorbisfile->srcpad, gst_vorbisfile_get_event_masks);
+  gst_pad_set_event_mask_function (vorbisfile->srcpad, 
+                                  gst_vorbisfile_get_event_masks);
   gst_pad_set_event_function (vorbisfile->srcpad, gst_vorbisfile_src_event);
   gst_pad_set_convert_function (vorbisfile->srcpad, gst_vorbisfile_src_convert);
 
@@ -218,8 +280,14 @@ gst_vorbisfile_init (VorbisFile * vorbisfile)
   vorbisfile->offset = 0;
   vorbisfile->seek_pending = 0;
   vorbisfile->need_discont = FALSE;
+  vorbisfile->get_metadata = TRUE;
+  vorbisfile->link = -1;       /* by default, ask for entire bitstream */
+  vorbisfile->metadata = NULL;
 }
 
+/* the next four functions are the ov callbacks we provide to vorbisfile
+ * which interface between GStreamer's handling of the data flow and
+ * vorbis's needs */
 static size_t
 gst_vorbisfile_read (void *ptr, size_t size, size_t nmemb, void *datasource)
 {
@@ -349,23 +417,95 @@ ov_callbacks vorbisfile_ov_callbacks =
   gst_vorbisfile_tell,
 };
 
+/* retrieve the comment field and put tags in metadata GstCaps
+ * returns TRUE if caps were still valid or could be set,
+ * FALSE if they couldn't be read somehow */
+static gboolean
+gst_vorbisfile_get_metadata (VorbisFile *vorbisfile)
+{
+  OggVorbis_File *vf = &vorbisfile->vf;
+  char **ptr;
+  int link = vorbisfile->link;
+  GstProps *props = NULL;
+  GstPropsEntry *entry;
+  gchar *name, *value;
+
+  /* check if we need to update or not */
+  if (vorbisfile->have_metadata)
+    return TRUE;
+
+  /* clear old one */
+  if (vorbisfile->metadata) {
+    gst_caps_unref (vorbisfile->metadata);
+    vorbisfile->metadata = NULL;
+  }
+
+  ptr = ov_comment (vf, link)->user_comments;
+  if (! (*ptr)) return FALSE;
+  props = gst_props_empty_new ();
+
+  while (*ptr) {
+    value = strstr (*ptr, "=");
+    if (value) {
+      *value = 0;
+      ++value;
+      name = *ptr;
+      entry = gst_props_entry_new (name, GST_PROPS_STRING_TYPE, value);
+      gst_props_add_entry (props, (GstPropsEntry *) entry);
+    }
+    ++ptr;
+  }
+
+  vorbisfile->have_metadata = TRUE;
+  vorbisfile->metadata = gst_caps_new ("vorbisfile_metadata",
+                                      "application/x-gst-metadata",
+                                      props);
+  return TRUE;
+}
+
+/* retrieve techical metadata and update vorbisfile with it */
+/* FIXME: write me */
+/* FIXME: make this less more expensive; only update it if the
+ * link id has changed */
+static void
+gst_vorbisfile_metadata_get_technical (VorbisFile *vorbisfile)
+{
+  OggVorbis_File *vf = &vorbisfile->vf;
+  //vorbis_info *vi;
+  //int link = vorbisfile->link;
+
+  /* check if we need to update or not */
+  if (vorbisfile->have_metadata_technical)
+    return;
+
+  /* FIXME: clear old one */
+
+  /* get number of streams */
+  vorbisfile->streams = ov_streams (vf);
+}
 static void
 gst_vorbisfile_loop (GstElement *element)
 {
   VorbisFile *vorbisfile = GST_VORBISFILE (element);
+  OggVorbis_File *vf = &vorbisfile->vf;
   GstBuffer *outbuf;
   long ret;
   GstClockTime time;
   gint64 samples;
 
+  /* this function needs to go first since you don't want to be messing
+   * with an unset vf ;) */
   if (vorbisfile->restart) {
     vorbisfile->current_section = 0;
     vorbisfile->offset = 0;
     vorbisfile->total_bytes = 0;
     vorbisfile->may_eos = FALSE;
-    vorbisfile->vf.seekable = gst_bytestream_seek (vorbisfile->bs, 0, GST_SEEK_METHOD_SET);
+    vorbisfile->vf.seekable = gst_bytestream_seek (vorbisfile->bs, 0, 
+                                                  GST_SEEK_METHOD_SET);
 
-    if (ov_open_callbacks (vorbisfile, &vorbisfile->vf, NULL, 0, vorbisfile_ov_callbacks) < 0) {
+    /* open our custom vorbisfile data object with the callbacks we provide */
+    if (ov_open_callbacks (vorbisfile, &vorbisfile->vf, NULL, 0, 
+                          vorbisfile_ov_callbacks) < 0) {
       gst_element_error (element, "this is not a vorbis file");
       return;
     }
@@ -373,33 +513,80 @@ gst_vorbisfile_loop (GstElement *element)
     vorbisfile->restart = FALSE;
   }
 
+  /* get relevant data if asked for */
+  if (vorbisfile->get_metadata) {
+    vorbis_info *vi;
+    double time_total;
+    ogg_int64_t raw_total;
+    int link = vorbisfile->link;
+
+    if (gst_vorbisfile_get_metadata (vorbisfile))
+      g_object_notify (G_OBJECT (vorbisfile), "metadata");
+
+
+    /* get stream metadata */
+    /* FIXME: due to a compiler bug, the actual vorbis bitrate function 
+     * doesn't return a good number ... */
+    vorbisfile->bitrate = ov_bitrate (vf, link);
+    if (vorbisfile->bitrate == OV_EINVAL)
+      g_warning ("OV_EINVAL: vf not open\n");
+    if (vorbisfile->bitrate == OV_FALSE)
+      g_warning ("OV_FALSE: non-seekable and no bitrate values set\n");
+
+    /* ... so we calculate it by hand, which should be done better
+     * by avoiding headers and stuff */
+     time_total = ov_time_total (vf, link);
+    raw_total = ov_raw_total (vf, link);
+    g_print ("total time: %f\n", time_total);
+    g_print ("abr: %d\n", 
+            (gint) ((guint64) raw_total / (guint64) time_total) * 8);
+    vi = ov_info (vf, link);
+    vorbisfile->version = vi->version;
+    vorbisfile->samplerate = vi->rate;
+    vorbisfile->channels = vi->channels;
+    vorbisfile->bitrate_upper = vi->bitrate_upper;
+    vorbisfile->bitrate_nominal = vi->bitrate_nominal;
+    vorbisfile->bitrate_lower = vi->bitrate_lower;
+    g_print ("Bitstream is %d channel, %ld Hz, %d version, %ld bitrate\n", 
+            vi->channels, vi->rate, vi->version, vorbisfile->bitrate);
+    g_print ("bitrate: %f\n", (double) vorbisfile->bitrate);
+    /* fire the signal saying we have metadata */
+    g_signal_emit (G_OBJECT(vorbisfile), 
+                  gst_vorbisfile_signals[SIGNAL_HAVE_METADATA], 0);
+    vorbisfile->get_metadata = FALSE;
+  }
   if (vorbisfile->seek_pending) {
+    /* get time to seek to in seconds */
+    gdouble seek_to = (gdouble) vorbisfile->seek_value / GST_SECOND;
+
     switch (vorbisfile->seek_format) {
       case GST_FORMAT_TIME:
        if (vorbisfile->seek_accurate) {
-          if (ov_time_seek (&vorbisfile->vf, (gdouble) vorbisfile->seek_value / GST_SECOND) == 0) {
+          if (ov_time_seek (&vorbisfile->vf, seek_to) == 0) {
             vorbisfile->need_discont = TRUE;
           }
         }
        else {
-          if (ov_time_seek_page (&vorbisfile->vf, (gdouble) vorbisfile->seek_value / GST_SECOND) == 0) {
+          if (ov_time_seek_page (&vorbisfile->vf, seek_to) == 0) {
             vorbisfile->need_discont = TRUE;
           }
        }
        break;
       case GST_FORMAT_UNITS:
        if (vorbisfile->seek_accurate) {
-          if (ov_pcm_seek (&vorbisfile->vf, (gdouble) vorbisfile->seek_value / GST_SECOND) == 0) {
+          if (ov_pcm_seek (&vorbisfile->vf, seek_to) == 0) {
             vorbisfile->need_discont = TRUE;
           }
         }
        else {
-          if (ov_pcm_seek_page (&vorbisfile->vf, (gdouble) vorbisfile->seek_value / GST_SECOND) == 0) {
+          if (ov_pcm_seek_page (&vorbisfile->vf, seek_to) == 0) {
             vorbisfile->need_discont = TRUE;
           }
        }
        break;
       default:
+       g_warning ("unknown seek method, implement me !");
        break;
     }
     vorbisfile->seek_pending = FALSE;
@@ -412,20 +599,23 @@ gst_vorbisfile_loop (GstElement *element)
   /* get current time for discont and buffer timestamp */
   time = (GstClockTime) (ov_time_tell (&vorbisfile->vf) * GST_SECOND);
 
-  ret = ov_read (&vorbisfile->vf, GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), 
-                 (G_BYTE_ORDER == G_LITTLE_ENDIAN ? 0 : 1), sizeof (gint16), 1, &vorbisfile->current_section);
+  ret = ov_read (&vorbisfile->vf, 
+                GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf), 
+                (G_BYTE_ORDER == G_LITTLE_ENDIAN ? 0 : 1), 
+                sizeof (gint16), 1, &vorbisfile->current_section);
 
   if (vorbisfile->need_discont) {
     GstEvent *discont;
 
     vorbisfile->need_discont = FALSE;
 
+    /* if the pad is not usable, don't push it out */
     if (GST_PAD_IS_USABLE (vorbisfile->srcpad)) {
       /* get stream stats */
       samples = (gint64) (ov_pcm_tell (&vorbisfile->vf));
 
       discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, 
-                                                 GST_FORMAT_UNITS, samples, NULL); 
+                                            GST_FORMAT_UNITS, samples, NULL); 
 
       gst_pad_push (vorbisfile->srcpad, GST_BUFFER (discont));
     }
@@ -433,11 +623,15 @@ gst_vorbisfile_loop (GstElement *element)
 
   if (ret == 0) {
     GST_DEBUG (0, "eos");
-    //ov_clear (&vorbisfile->vf);
+    /* send EOS event */
+    /*FIXME: should we do this or not ?
+    ov_clear (&vorbisfile->vf);*/
     vorbisfile->restart = TRUE;
     gst_buffer_unref (outbuf);
+    /* if the pad is not usable, don't push it out */
     if (GST_PAD_IS_USABLE (vorbisfile->srcpad)) 
-      gst_pad_push (vorbisfile->srcpad, GST_BUFFER (gst_event_new (GST_EVENT_EOS)));
+      gst_pad_push (vorbisfile->srcpad, 
+                   GST_BUFFER (gst_event_new (GST_EVENT_EOS)));
     gst_element_set_eos (element);
     return;
   }
@@ -453,19 +647,20 @@ gst_vorbisfile_loop (GstElement *element)
       
       if (gst_pad_try_set_caps (vorbisfile->srcpad,
                    GST_CAPS_NEW ("vorbisdec_src",
-                                    "audio/raw",    
-                                      "format",     GST_PROPS_STRING ("int"),
-                                      "law",        GST_PROPS_INT (0),
-                                      "endianness", GST_PROPS_INT (G_BYTE_ORDER),
-                                      "signed",     GST_PROPS_BOOLEAN (TRUE),
-                                      "width",      GST_PROPS_INT (16),
-                                      "depth",      GST_PROPS_INT (16),
-                                      "rate",       GST_PROPS_INT (vi->rate),
-                                      "channels",   GST_PROPS_INT (vi->channels)
-                                     )) <= 0) 
+                                   "audio/raw",    
+                                     "format",     GST_PROPS_STRING ("int"),
+                                     "law",        GST_PROPS_INT (0),
+                                     "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+                                     "signed",     GST_PROPS_BOOLEAN (TRUE),
+                                     "width",      GST_PROPS_INT (16),
+                                     "depth",      GST_PROPS_INT (16),
+                                     "rate",       GST_PROPS_INT (vi->rate),
+                                     "channels",   GST_PROPS_INT (vi->channels)
+                                )) <= 0) 
       {
         gst_buffer_unref (outbuf);
-       gst_element_error (GST_ELEMENT (vorbisfile), "could not negotiate format");
+       gst_element_error (GST_ELEMENT (vorbisfile), 
+                          "could not negotiate format");
        return;
       }
     }
@@ -497,8 +692,11 @@ gst_vorbisfile_get_formats (GstPad *pad)
   return formats;
 }
 
+/* handles conversion of location offsets between two formats based on
+ * src caps */
 static gboolean
-gst_vorbisfile_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
+gst_vorbisfile_src_convert (GstPad *pad, 
+                           GstFormat src_format, gint64 src_value,
                            GstFormat *dest_format, gint64 *dest_value)
 {
   gboolean res = TRUE;
@@ -579,7 +777,8 @@ gst_vorbisfile_get_query_types (GstPad *pad)
   };
   return types;
 }
-                   
+
+/* handles queries for location in the stream in the requested format */
 static gboolean
 gst_vorbisfile_src_query (GstPad *pad, GstPadQueryType type,
                          GstFormat *format, gint64 *value)
@@ -632,7 +831,8 @@ gst_vorbisfile_src_query (GstPad *pad, GstPadQueryType type,
           if (vorbisfile->vf.seekable)
            *value = (gint64) (ov_time_tell (&vorbisfile->vf) * GST_SECOND);
          else
-            *value = vorbisfile->total_bytes * GST_SECOND / (vi->rate * vi->channels * 2);
+            *value = vorbisfile->total_bytes * GST_SECOND 
+                                            / (vi->rate * vi->channels * 2);
          break;
         case GST_FORMAT_BYTES:
           if (vorbisfile->vf.seekable)
@@ -668,7 +868,8 @@ gst_vorbisfile_get_event_masks (GstPad *pad)
   };
   return masks;
 }
-                   
+
+/* handle events on src pad */
 static gboolean
 gst_vorbisfile_src_event (GstPad *pad, GstEvent *event)
 {
@@ -695,7 +896,8 @@ gst_vorbisfile_src_event (GstPad *pad, GstEvent *event)
          vorbisfile->seek_pending = TRUE;
          vorbisfile->seek_value = offset;
          vorbisfile->seek_format = GST_FORMAT_TIME;
-         vorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_ACCURATE;
+         vorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event) 
+                                   & GST_SEEK_FLAG_ACCURATE;
          break;
        case GST_FORMAT_BYTES:
           vi = ov_info (&vorbisfile->vf, -1);
@@ -709,7 +911,8 @@ gst_vorbisfile_src_event (GstPad *pad, GstEvent *event)
          vorbisfile->seek_pending = TRUE;
          vorbisfile->seek_value = offset;
          vorbisfile->seek_format = GST_FORMAT_UNITS;
-         vorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_ACCURATE;
+         vorbisfile->seek_accurate = GST_EVENT_SEEK_FLAGS (event) 
+                                   & GST_SEEK_FLAG_ACCURATE;
          break;
        default:
          res = FALSE;
@@ -757,8 +960,30 @@ gst_vorbisfile_change_state (GstElement *element)
   return GST_STATE_SUCCESS;
 }
 
+static void
+gst_vorbisfile_set_property (GObject *object, guint prop_id, 
+                            const GValue *value, GParamSpec *pspec)
+{
+  VorbisFile *vorbisfile;
+             
+  g_return_if_fail (GST_IS_VORBISFILE (object));
+
+  vorbisfile = GST_VORBISFILE (object);
+
+  switch (prop_id) {
+    case ARG_METADATA:
+      break;
+    case ARG_LINK:
+      vorbisfile->link = g_value_get_int (value);
+      break;
+    default:
+      g_warning ("Unknown property id\n");
+  }
+}
+
 static void 
-gst_vorbisfile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+gst_vorbisfile_get_property (GObject *object, guint prop_id, 
+                            GValue *value, GParamSpec *pspec)
 {
   VorbisFile *vorbisfile;
              
@@ -766,9 +991,11 @@ gst_vorbisfile_get_property (GObject *object, guint prop_id, GValue *value, GPar
 
   vorbisfile = GST_VORBISFILE (object);
 
+  /* FIXME: the reupdate could be expensive */
   switch (prop_id) {
-    case ARG_COMMENT:
-      g_value_set_string (value, "comment");
+    case ARG_METADATA:
+      gst_vorbisfile_get_metadata (vorbisfile);
+      g_value_set_boxed (value, vorbisfile->metadata);
       break;
     case ARG_VENDOR:
       break;
@@ -778,6 +1005,14 @@ gst_vorbisfile_get_property (GObject *object, guint prop_id, GValue *value, GPar
       break;
     case ARG_RATE:
       break;
+    case ARG_STREAMS:
+      gst_vorbisfile_metadata_get_technical (vorbisfile);
+      g_value_set_int (value, vorbisfile->streams);
+      break;
+    case ARG_LINK:
+      break;
+    case ARG_BITRATE:
+      break;
     case ARG_BITRATE_UPPER:
       break;
     case ARG_BITRATE_NOMINAL:
@@ -786,5 +1021,7 @@ gst_vorbisfile_get_property (GObject *object, guint prop_id, GValue *value, GPar
       break;
     case ARG_BITRATE_WINDOW:
       break;
+    default:
+      g_warning ("Unknown property id\n");
   }
 }