[nautilus/wip/hadess/audio-video-properties: 1/3] Add copy/paste of totem's properties window nautilus extension



commit e1c51c159c0782f93e781bef278e88abb44df5e2
Author: Bastien Nocera <hadess hadess net>
Date:   Mon Feb 11 13:17:35 2019 +0100

    Add copy/paste of totem's properties window nautilus extension
    
    Direct copy/paste from totem, no wider build system integration.

 .../bacon-video-widget-properties.c                | 286 +++++++++
 .../bacon-video-widget-properties.h                |  62 ++
 extensions/audio-video-properties/meson.build      |  42 ++
 extensions/audio-video-properties/properties.ui    | 692 +++++++++++++++++++++
 .../audio-video-properties/test-properties-page.c  |  87 +++
 .../audio-video-properties/totem-properties-main.c | 160 +++++
 .../audio-video-properties/totem-properties-view.c | 395 ++++++++++++
 .../audio-video-properties/totem-properties-view.h |  57 ++
 8 files changed, 1781 insertions(+)
---
diff --git a/extensions/audio-video-properties/bacon-video-widget-properties.c 
b/extensions/audio-video-properties/bacon-video-widget-properties.c
new file mode 100644
index 000000000..188445624
--- /dev/null
+++ b/extensions/audio-video-properties/bacon-video-widget-properties.c
@@ -0,0 +1,286 @@
+/* bacon-video-widget-properties.c
+
+   Copyright (C) 2002 Bastien Nocera
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301  USA.
+
+   Author: Bastien Nocera <hadess hadess net>
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+
+#include "totem-interface.h"
+
+#include "bacon-video-widget-properties.h"
+
+static void bacon_video_widget_properties_dispose (GObject *object);
+
+struct BaconVideoWidgetPropertiesPrivate {
+       GtkBuilder *xml;
+       int time;
+};
+
+#define BACON_VIDEO_WIDGET_PROPERTIES_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), 
BACON_TYPE_VIDEO_WIDGET_PROPERTIES, BaconVideoWidgetPropertiesPrivate))
+
+G_DEFINE_TYPE (BaconVideoWidgetProperties, bacon_video_widget_properties, GTK_TYPE_BOX)
+
+static void
+bacon_video_widget_properties_class_init (BaconVideoWidgetPropertiesClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (BaconVideoWidgetPropertiesPrivate));
+
+       object_class->dispose = bacon_video_widget_properties_dispose;
+}
+
+static void
+bacon_video_widget_properties_init (BaconVideoWidgetProperties *props)
+{
+       props->priv = G_TYPE_INSTANCE_GET_PRIVATE (props, BACON_TYPE_VIDEO_WIDGET_PROPERTIES, 
BaconVideoWidgetPropertiesPrivate);
+
+       gtk_orientable_set_orientation (GTK_ORIENTABLE (props), GTK_ORIENTATION_VERTICAL);
+}
+
+static void
+bacon_video_widget_properties_dispose (GObject *object)
+{
+       BaconVideoWidgetPropertiesPrivate *priv = BACON_VIDEO_WIDGET_PROPERTIES_GET_PRIVATE (object);
+
+       if (priv->xml != NULL)
+               g_object_unref (priv->xml);
+       priv->xml = NULL;
+
+       G_OBJECT_CLASS (bacon_video_widget_properties_parent_class)->dispose (object);
+}
+
+void
+bacon_video_widget_properties_set_label (BaconVideoWidgetProperties *props,
+                                        const char                 *name,
+                                        const char                 *text)
+{
+       GtkLabel *item;
+
+       g_return_if_fail (props != NULL);
+       g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+       g_return_if_fail (name != NULL);
+
+       item = GTK_LABEL (gtk_builder_get_object (props->priv->xml, name));
+       g_return_if_fail (item != NULL);
+       gtk_label_set_text (item, text);
+}
+
+void
+bacon_video_widget_properties_reset (BaconVideoWidgetProperties *props)
+{
+       GtkWidget *item;
+
+       g_return_if_fail (props != NULL);
+       g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+       item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video_vbox"));
+       gtk_widget_show (item);
+       item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video"));
+       gtk_widget_set_sensitive (item, FALSE);
+       item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "audio"));
+       gtk_widget_set_sensitive (item, FALSE);
+
+       /* Title */
+       bacon_video_widget_properties_set_label (props, "title", _("Unknown"));
+       /* Artist */
+       bacon_video_widget_properties_set_label (props, "artist", _("Unknown"));
+       /* Album */
+       bacon_video_widget_properties_set_label (props, "album", _("Unknown"));
+       /* Year */
+       bacon_video_widget_properties_set_label (props, "year", _("Unknown"));
+       /* Duration */
+       bacon_video_widget_properties_set_duration (props, 0);
+       /* Comment */
+       bacon_video_widget_properties_set_label (props, "comment", "");
+       /* Container */
+       bacon_video_widget_properties_set_label (props, "container", _("Unknown"));
+
+       /* Dimensions */
+       bacon_video_widget_properties_set_label (props, "dimensions", C_("Dimensions", "N/A"));
+       /* Video Codec */
+       bacon_video_widget_properties_set_label (props, "vcodec", C_("Video codec", "N/A"));
+       /* Video Bitrate */
+       bacon_video_widget_properties_set_label (props, "video_bitrate",
+                       C_("Video bit rate", "N/A"));
+       /* Framerate */
+       bacon_video_widget_properties_set_label (props, "framerate",
+                       C_("Frame rate", "N/A"));
+
+       /* Audio Bitrate */
+       bacon_video_widget_properties_set_label (props, "audio_bitrate",
+                       C_("Audio bit rate", "N/A"));
+       /* Audio Codec */
+       bacon_video_widget_properties_set_label (props, "acodec", C_("Audio codec", "N/A"));
+       /* Sample rate */
+       bacon_video_widget_properties_set_label (props, "samplerate", _("0 Hz"));
+       /* Channels */
+       bacon_video_widget_properties_set_label (props, "channels", _("0 Channels"));
+}
+
+static char *
+time_to_string_text (gint64 msecs)
+{
+       char *secs, *mins, *hours, *string;
+       int sec, min, hour, _time;
+
+       _time = (int) (msecs / 1000);
+       sec = _time % 60;
+       _time = _time - sec;
+       min = (_time % (60*60)) / 60;
+       _time = _time - (min * 60);
+       hour = _time / (60*60);
+
+       hours = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d hour", "%d hours", hour), hour);
+
+       mins = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d minute",
+                                         "%d minutes", min), min);
+
+       secs = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d second",
+                                         "%d seconds", sec), sec);
+
+       if (hour > 0)
+       {
+               /* 5 hours 2 minutes 12 seconds */
+               string = g_strdup_printf (C_("time", "%s %s %s"), hours, mins, secs);
+       } else if (min > 0) {
+               /* 2 minutes 12 seconds */
+               string = g_strdup_printf (C_("time", "%s %s"), mins, secs);
+       } else if (sec > 0) {
+               /* 10 seconds */
+               string = g_strdup (secs);
+       } else {
+               /* 0 seconds */
+               string = g_strdup (_("0 seconds"));
+       }
+
+       g_free (hours);
+       g_free (mins);
+       g_free (secs);
+
+       return string;
+}
+
+void
+bacon_video_widget_properties_set_duration (BaconVideoWidgetProperties *props,
+                                           int _time)
+{
+       char *string;
+
+       g_return_if_fail (props != NULL);
+       g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+       if (_time == props->priv->time)
+               return;
+
+       string = time_to_string_text (_time);
+       bacon_video_widget_properties_set_label (props, "duration", string);
+       g_free (string);
+
+       props->priv->time = _time;
+}
+
+void
+bacon_video_widget_properties_set_has_type (BaconVideoWidgetProperties *props,
+                                           gboolean                    has_video,
+                                           gboolean                    has_audio)
+{
+       GtkWidget *item;
+
+       g_return_if_fail (props != NULL);
+       g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+       /* Video */
+       item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video"));
+       gtk_widget_set_sensitive (item, has_video);
+       item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "video_vbox"));
+       gtk_widget_set_visible (item, has_video);
+
+       /* Audio */
+       item = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "audio"));
+       gtk_widget_set_sensitive (item, has_audio);
+}
+
+void
+bacon_video_widget_properties_set_framerate (BaconVideoWidgetProperties *props,
+                                            int                         framerate)
+{
+       gchar *temp;
+
+       g_return_if_fail (props != NULL);
+       g_return_if_fail (BACON_IS_VIDEO_WIDGET_PROPERTIES (props));
+
+       /* The FPS has to be done differently because it's a plural string */
+       if (framerate != 0) {
+               temp = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d frame per second", "%d frames per 
second", framerate),
+                                       framerate);
+       } else {
+               temp = g_strdup (C_("Frame rate", "N/A"));
+       }
+       bacon_video_widget_properties_set_label (props, "framerate", temp);
+       g_free (temp);
+}
+
+GtkWidget*
+bacon_video_widget_properties_new (void)
+{
+       BaconVideoWidgetProperties *props;
+       GtkBuilder *xml;
+       GtkWidget *vbox;
+       GtkSizeGroup *group;
+       const char *labels[] = { "title_label", "artist_label", "album_label",
+                       "year_label", "duration_label", "comment_label", "container_label",
+                       "dimensions_label", "vcodec_label", "framerate_label",
+                       "vbitrate_label", "abitrate_label", "acodec_label",
+                       "samplerate_label", "channels_label" };
+       guint i;
+
+       xml = gtk_builder_new ();
+       gtk_builder_set_translation_domain (xml, GETTEXT_PACKAGE);
+       if (gtk_builder_add_from_file (xml, DATADIR"/properties.ui", NULL) == 0) {
+               g_object_unref (xml);
+               return NULL;
+       }
+
+       props = BACON_VIDEO_WIDGET_PROPERTIES (g_object_new
+                       (BACON_TYPE_VIDEO_WIDGET_PROPERTIES, NULL));
+
+       props->priv->xml = xml;
+       vbox = GTK_WIDGET (gtk_builder_get_object (props->priv->xml, "vbox1"));
+       gtk_box_pack_start (GTK_BOX (props), vbox, FALSE, FALSE, 0);
+
+       bacon_video_widget_properties_reset (props);
+
+       group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+       for (i = 0; i < G_N_ELEMENTS (labels); i++)
+               gtk_size_group_add_widget (group, GTK_WIDGET (gtk_builder_get_object (xml, labels[i])));
+
+       g_object_unref (group);
+
+       gtk_widget_show_all (GTK_WIDGET (props));
+
+       return GTK_WIDGET (props);
+}
+
diff --git a/extensions/audio-video-properties/bacon-video-widget-properties.h 
b/extensions/audio-video-properties/bacon-video-widget-properties.h
new file mode 100644
index 000000000..cef7e53e9
--- /dev/null
+++ b/extensions/audio-video-properties/bacon-video-widget-properties.h
@@ -0,0 +1,62 @@
+/* bacon-video-widget-properties.h: Properties dialog for BaconVideoWidget
+
+   Copyright (C) 2002 Bastien Nocera <hadess hadess net>
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301  USA.
+
+   Author: Bastien Nocera <hadess hadess net>
+ */
+
+#ifndef BACON_VIDEO_WIDGET_PROPERTIES_H
+#define BACON_VIDEO_WIDGET_PROPERTIES_H
+
+#include <gtk/gtk.h>
+
+#define BACON_TYPE_VIDEO_WIDGET_PROPERTIES            (bacon_video_widget_properties_get_type ())
+#define BACON_VIDEO_WIDGET_PROPERTIES(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
BACON_TYPE_VIDEO_WIDGET_PROPERTIES, BaconVideoWidgetProperties))
+#define BACON_VIDEO_WIDGET_PROPERTIES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
BACON_TYPE_VIDEO_WIDGET_PROPERTIES, BaconVideoWidgetPropertiesClass))
+#define BACON_IS_VIDEO_WIDGET_PROPERTIES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
BACON_TYPE_VIDEO_WIDGET_PROPERTIES))
+#define BACON_IS_VIDEO_WIDGET_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
BACON_TYPE_VIDEO_WIDGET_PROPERTIES))
+
+typedef struct BaconVideoWidgetProperties              BaconVideoWidgetProperties;
+typedef struct BaconVideoWidgetPropertiesClass         BaconVideoWidgetPropertiesClass;
+typedef struct BaconVideoWidgetPropertiesPrivate       BaconVideoWidgetPropertiesPrivate;
+
+struct BaconVideoWidgetProperties {
+       GtkBox parent;
+       BaconVideoWidgetPropertiesPrivate *priv;
+};
+
+struct BaconVideoWidgetPropertiesClass {
+       GtkBoxClass parent_class;
+};
+
+GType bacon_video_widget_properties_get_type           (void);
+GtkWidget *bacon_video_widget_properties_new           (void);
+
+void bacon_video_widget_properties_reset               (BaconVideoWidgetProperties *props);
+void bacon_video_widget_properties_set_label           (BaconVideoWidgetProperties *props,
+                                                        const char                 *name,
+                                                        const char                 *text);
+void bacon_video_widget_properties_set_duration                (BaconVideoWidgetProperties *props,
+                                                        int                         duration);
+void bacon_video_widget_properties_set_has_type                (BaconVideoWidgetProperties *props,
+                                                        gboolean                    has_video,
+                                                        gboolean                    has_audio);
+void bacon_video_widget_properties_set_framerate       (BaconVideoWidgetProperties *props,
+                                                        int                         framerate);
+
+#endif /* BACON_VIDEO_WIDGET_PROPERTIES_H */
diff --git a/extensions/audio-video-properties/meson.build b/extensions/audio-video-properties/meson.build
new file mode 100644
index 000000000..9116a3bde
--- /dev/null
+++ b/extensions/audio-video-properties/meson.build
@@ -0,0 +1,42 @@
+libtotem_properties_page_sources = files(
+  'totem-properties-main.c',
+  'totem-properties-view.c'
+)
+
+libtotem_properties_page_deps = missing_plugins_deps + [
+  gtk_dep,
+  dependency('gthread-2.0'),
+  libnautilus_ext_dep,
+  gst_tag_dep,
+  libbacon_video_widget_properties_dep
+]
+
+libtotem_properties_page = shared_module(
+  'totem-properties-page',
+  sources: libtotem_properties_page_sources + gen_sources,
+  include_directories: top_inc,
+  dependencies: libtotem_properties_page_deps,
+  c_args: totem_common_cflags + [
+    '-DG_LOG_DOMAIN="TotemPropertiesPage"'
+  ],
+  install: true,
+  install_dir: nautilusdir
+)
+
+test_properties_page_sources = files(
+  'totem-properties-main.c',
+  'totem-properties-view.c',
+  'test-properties-page.c'
+)
+
+executable(
+  'test-properties-page',
+  test_properties_page_sources + gen_sources,
+  include_directories: top_inc,
+  dependencies: libtotem_properties_page_deps + [
+    libtotem_player_dep,
+    libbacon_video_widget_dep
+  ],
+  c_args: totem_common_cflags
+)
+
diff --git a/extensions/audio-video-properties/properties.ui b/extensions/audio-video-properties/properties.ui
new file mode 100644
index 000000000..eed91f9f8
--- /dev/null
+++ b/extensions/audio-video-properties/properties.ui
@@ -0,0 +1,692 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.11"/>
+  <object class="GtkBox" id="vbox1">
+    <property name="width_request">375</property>
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="margin_bottom">12</property>
+    <property name="border_width">6</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">18</property>
+    <child>
+      <object class="GtkBox" id="general_vbox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="bvwp_general_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">General</property>
+            <property name="use_markup">True</property>
+            <property name="xalign">0</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="general">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">12</property>
+            <child>
+              <object class="GtkLabel" id="title_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Title:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="title"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="artist_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Artist:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="artist"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="duration_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Duration:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="duration"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="year_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Year:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="year"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="album_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Album:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="album"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="title">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">Unknown</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="title_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="artist">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">Unknown</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="artist_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="album">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">Unknown</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="album_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="year">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">Unknown</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="year_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="duration">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">0 seconds</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="duration_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="comment_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Comment:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="comment"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">5</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="comment">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">Unknown</property>
+                <property name="wrap">True</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="comment_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">5</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="container_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Container:</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">6</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="container">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label">Unknown</property>
+                <property name="selectable">True</property>
+                <property name="xalign">0</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">6</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox" id="video_vbox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="bvwp_video_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Video</property>
+            <property name="use_markup">True</property>
+            <property name="xalign">0</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="video">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">12</property>
+            <child>
+              <object class="GtkLabel" id="dimensions_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Dimensions:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="dimensions"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="vcodec_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Codec:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="vcodec"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="framerate_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Framerate:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="framerate"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="vbitrate_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Bitrate:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="video_bitrate"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="dimensions">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">0 x 0</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="dimensions_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="vcodec">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">N/A</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="vcodec_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="framerate">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">0 frames per second</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="framerate_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="video_bitrate">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">0 kbps</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="vbitrate_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox" id="audio_vbox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="bvwp_audio_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Audio</property>
+            <property name="use_markup">True</property>
+            <property name="xalign">0</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="audio">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">12</property>
+            <child>
+              <object class="GtkLabel" id="samplerate_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Sample rate:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="samplerate"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="samplerate">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">0 Hz</property>
+                <property name="selectable">True</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="samplerate_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="abitrate_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Bitrate:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="audio_bitrate"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="audio_bitrate">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">0 kbps</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="abitrate_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="acodec_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Codec:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="acodec"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="acodec">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">N/A</property>
+                <property name="selectable">True</property>
+                <property name="ellipsize">end</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="acodec_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="channels_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_start">12</property>
+                <property name="label" translatable="yes">Channels:</property>
+                <property name="use_markup">True</property>
+                <property name="xalign">0</property>
+                <attributes>
+                  <attribute name="style" value="italic"/>
+                </attributes>
+                <accessibility>
+                  <relation type="label-for" target="channels"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="channels">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label">0 Channels</property>
+                <property name="selectable">True</property>
+                <property name="xalign">0</property>
+                <accessibility>
+                  <relation type="labelled-by" target="channels_label"/>
+                </accessibility>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/extensions/audio-video-properties/test-properties-page.c 
b/extensions/audio-video-properties/test-properties-page.c
new file mode 100644
index 000000000..8dd3f2e33
--- /dev/null
+++ b/extensions/audio-video-properties/test-properties-page.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2005  Bastien Nocera <hadess hadess net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#define GST_USE_UNSTABLE_API 1
+#include <gst/gst.h>
+#include <glib/gi18n-lib.h>
+#include "totem-properties-view.h"
+
+static GtkWidget *window, *props, *label;
+
+static void
+create_props (const char *url)
+{
+       label = gtk_label_new ("Audio/Video");
+       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+       g_signal_connect (G_OBJECT (window), "destroy",
+                         G_CALLBACK (gtk_main_quit), NULL);
+       gtk_window_set_default_size (GTK_WINDOW (window), 450, 550);
+       props = totem_properties_view_new (url, label);
+       gtk_container_add (GTK_CONTAINER (window), props);
+
+       gtk_widget_show_all (window);
+}
+
+static void
+destroy_props (void)
+{
+       gtk_widget_destroy (label);
+}
+
+int main (int argc, char **argv)
+{
+       GFile *file;
+       char *url;
+
+       bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+       textdomain (GETTEXT_PACKAGE);
+
+       gst_init (&argc, &argv);
+       gtk_init (&argc, &argv);
+
+       if (argc != 2) {
+               g_print ("Usage: %s [URI]\n", argv[0]);
+               return 1;
+       }
+
+       file = g_file_new_for_commandline_arg (argv[1]);
+       url = g_file_get_uri (file);
+       g_object_unref (file);
+
+       create_props (url);
+       g_free (url);
+
+       gtk_main ();
+
+       destroy_props ();
+
+       return 0;
+}
+
diff --git a/extensions/audio-video-properties/totem-properties-main.c 
b/extensions/audio-video-properties/totem-properties-main.c
new file mode 100644
index 000000000..4a60489a2
--- /dev/null
+++ b/extensions/audio-video-properties/totem-properties-main.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2000, 2001 Eazel Inc.
+ * Copyright (C) 2003  Andrew Sobala <aes gnome org>
+ * Copyright (C) 2005  Bastien Nocera <hadess hadess net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#define GST_USE_UNSTABLE_API 1
+#include <gst/gst.h>
+
+#include "gst/totem-gst-helpers.h"
+#include "totem-properties-view.h"
+#include <libnautilus-extension/nautilus-extension-types.h>
+#include <libnautilus-extension/nautilus-property-page-provider.h>
+
+#define WANT_MIME_TYPES 1
+#include "totem-mime-types.h"
+
+static GType tpp_type = 0;
+static void property_page_provider_iface_init
+       (NautilusPropertyPageProviderIface *iface);
+static GList *totem_properties_get_pages
+       (NautilusPropertyPageProvider *provider, GList *files);
+
+static void
+totem_properties_plugin_register_type (GTypeModule *module)
+{
+       const GTypeInfo info = {
+               sizeof (GObjectClass),
+               (GBaseInitFunc) NULL,
+               (GBaseFinalizeFunc) NULL,
+               (GClassInitFunc) NULL,
+               NULL,
+               NULL,
+               sizeof (GObject),
+               0,
+               (GInstanceInitFunc) NULL
+       };
+       const GInterfaceInfo property_page_provider_iface_info = {
+               (GInterfaceInitFunc)property_page_provider_iface_init,
+               NULL,
+               NULL
+       };
+
+       tpp_type = g_type_module_register_type (module, G_TYPE_OBJECT,
+                       "TotemPropertiesPlugin",
+                       &info, 0);
+       g_type_module_add_interface (module,
+                       tpp_type,
+                       NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER,
+                       &property_page_provider_iface_info);
+}
+
+static void
+property_page_provider_iface_init (NautilusPropertyPageProviderIface *iface)
+{
+       iface->get_pages = totem_properties_get_pages;
+}
+
+static gpointer
+init_backend (gpointer data)
+{
+       gst_init (NULL, NULL);
+       totem_gst_disable_display_decoders ();
+       return NULL;
+}
+
+static GList *
+totem_properties_get_pages (NautilusPropertyPageProvider *provider,
+                            GList *files)
+{
+       static GOnce backend_inited = G_ONCE_INIT;
+       NautilusFileInfo *file;
+       char *uri;
+       GtkWidget *page, *label;
+       NautilusPropertyPage *property_page;
+       guint i;
+       gboolean found;
+
+       /* only add properties page if a single file is selected */
+       if (files == NULL || files->next != NULL)
+               return NULL;
+       file = files->data;
+
+       /* only add the properties page to these mime types */
+       found = FALSE;
+       for (i = 0; mime_types[i] != NULL; i++) {
+               if (nautilus_file_info_is_mime_type (file, mime_types[i])) {
+                       found = TRUE;
+                       break;
+               }
+       }
+       if (found == FALSE)
+               return NULL;
+
+       /* okay, make the page, init'ing the backend first if necessary */
+       g_once (&backend_inited, init_backend, NULL);
+
+       uri = nautilus_file_info_get_uri (file);
+       label = gtk_label_new (_("Audio/Video"));
+       page = totem_properties_view_new (uri, label);
+       g_free (uri);
+
+       gtk_container_set_border_width (GTK_CONTAINER (page), 6);
+       property_page = nautilus_property_page_new ("video-properties",
+                       label, page);
+
+       return g_list_prepend (NULL, property_page);
+}
+
+/* --- extension interface --- */
+void
+nautilus_module_initialize (GTypeModule *module)
+{
+       /* set up translation catalog */
+       bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+       totem_properties_plugin_register_type (module);
+       totem_properties_view_register_type (module);
+}
+
+void
+nautilus_module_shutdown (void)
+{
+}
+
+void
+nautilus_module_list_types (const GType **types,
+                            int          *num_types)
+{
+       static GType type_list[1];
+
+       type_list[0] = tpp_type;
+       *types = type_list;
+       *num_types = G_N_ELEMENTS (type_list);
+}
+
diff --git a/extensions/audio-video-properties/totem-properties-view.c 
b/extensions/audio-video-properties/totem-properties-view.c
new file mode 100644
index 000000000..51c1334ef
--- /dev/null
+++ b/extensions/audio-video-properties/totem-properties-view.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2003  Andrew Sobala <aes gnome org>
+ * Copyright (C) 2004  Bastien Nocera <hadess hadess net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ *
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+
+#define GST_USE_UNSTABLE_API 1
+#include <gst/tag/tag.h>
+#include <gst/pbutils/pbutils.h>
+
+#include "totem-properties-view.h"
+#include "bacon-video-widget-properties.h"
+
+struct TotemPropertiesViewPriv {
+       GtkWidget *label;
+       GtkWidget *vbox;
+       BaconVideoWidgetProperties *props;
+       GstDiscoverer *disco;
+};
+
+static GObjectClass *parent_class = NULL;
+static void totem_properties_view_finalize (GObject *object);
+
+G_DEFINE_TYPE (TotemPropertiesView, totem_properties_view, GTK_TYPE_GRID)
+
+void
+totem_properties_view_register_type (GTypeModule *module)
+{
+       totem_properties_view_get_type ();
+}
+
+static void
+totem_properties_view_class_init (TotemPropertiesViewClass *class)
+{
+       parent_class = g_type_class_peek_parent (class);
+       G_OBJECT_CLASS (class)->finalize = totem_properties_view_finalize;
+}
+
+static void
+update_general (TotemPropertiesView *props,
+               const GstTagList    *list)
+{
+       struct {
+               const char *tag_name;
+               const char *widget;
+       } items[] = {
+               { GST_TAG_TITLE, "title" },
+               { GST_TAG_ARTIST, "artist" },
+               { GST_TAG_ALBUM, "album" },
+       };
+       guint i;
+        GDate *date;
+       GstDateTime *datetime;
+       gchar *comment;
+
+       for (i = 0; i < G_N_ELEMENTS(items); i++) {
+               char *string;
+
+               if (gst_tag_list_get_string_index (list, items[i].tag_name, 0, &string) != FALSE) {
+                       bacon_video_widget_properties_set_label (props->priv->props,
+                                                                items[i].widget,
+                                                                string);
+                       g_free (string);
+               }
+       }
+       
+       /* Comment else use Description defined by:
+        * http://xiph.org/vorbis/doc/v-comment.html */
+       if (gst_tag_list_get_string (list, GST_TAG_COMMENT, &comment) ||
+               gst_tag_list_get_string (list, GST_TAG_DESCRIPTION, &comment)) {
+
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        "comment",
+                                                        comment);
+               g_free (comment);
+        }
+       
+       /* Date */
+        if (gst_tag_list_get_date (list, GST_TAG_DATE, &date)) {
+               char *string;
+
+               string = g_strdup_printf ("%d", g_date_get_year (date));
+               g_date_free (date);
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        "year",
+                                                        string);
+               g_free (string);
+        } else if (gst_tag_list_get_date_time (list, GST_TAG_DATE_TIME, &datetime)) {
+               char *string;
+
+               string = g_strdup_printf ("%d", gst_date_time_get_year (datetime));
+               gst_date_time_unref (datetime);
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        "year",
+                                                        string);
+               g_free (string);
+       }
+}
+
+static void
+set_codec (TotemPropertiesView     *props,
+          GstDiscovererStreamInfo *info,
+          const char              *widget)
+{
+       GstCaps *caps;
+       const char *nick;
+
+       nick = gst_discoverer_stream_info_get_stream_type_nick (info);
+       if (g_str_equal (nick, "audio") == FALSE &&
+           g_str_equal (nick, "video") == FALSE &&
+           g_str_equal (nick, "container") == FALSE) {
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        widget,
+                                                        _("N/A"));
+               return;
+       }
+
+       caps = gst_discoverer_stream_info_get_caps (info);
+       if (caps) {
+               if (gst_caps_is_fixed (caps)) {
+                       char *string;
+
+                       string = gst_pb_utils_get_codec_description (caps);
+                       bacon_video_widget_properties_set_label (props->priv->props,
+                                                                widget,
+                                                                string);
+                       g_free (string);
+               }
+               gst_caps_unref (caps);
+       }
+}
+
+static void
+set_bitrate (TotemPropertiesView    *props,
+            guint                   bitrate,
+            const char             *widget)
+{
+       char *string;
+
+       if (!bitrate) {
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        widget,
+                                                        C_("Stream bit rate", "N/A"));
+               return;
+       }
+       string = g_strdup_printf (_("%d kbps"), bitrate / 1000);
+       bacon_video_widget_properties_set_label (props->priv->props,
+                                                widget,
+                                                string);
+       g_free (string);
+}
+
+static void
+update_video (TotemPropertiesView    *props,
+             GstDiscovererVideoInfo *info)
+{
+       guint width, height;
+       guint fps_n, fps_d;
+       char *string;
+
+       width = gst_discoverer_video_info_get_width (info);
+       height = gst_discoverer_video_info_get_height (info);
+       string = g_strdup_printf (N_("%d × %d"), width, height);
+       bacon_video_widget_properties_set_label (props->priv->props,
+                                                "dimensions",
+                                                string);
+       g_free (string);
+
+       set_codec (props, (GstDiscovererStreamInfo *) info, "vcodec");
+       set_bitrate (props, gst_discoverer_video_info_get_bitrate (info), "video_bitrate");
+
+       /* Round up/down to the nearest integer framerate */
+       fps_n = gst_discoverer_video_info_get_framerate_num (info);
+       fps_d = gst_discoverer_video_info_get_framerate_denom (info);
+       if (fps_d == 0)
+               bacon_video_widget_properties_set_framerate (props->priv->props, 0);
+       else
+               bacon_video_widget_properties_set_framerate (props->priv->props,
+                                                            (fps_n + fps_d/2) / fps_d);
+}
+
+static void
+update_audio (TotemPropertiesView    *props,
+             GstDiscovererAudioInfo *info)
+{
+       guint samplerate, channels;
+
+       set_codec (props, (GstDiscovererStreamInfo *) info, "acodec");
+
+       set_bitrate (props, gst_discoverer_audio_info_get_bitrate (info), "audio_bitrate");
+
+       samplerate = gst_discoverer_audio_info_get_sample_rate (info);
+       if (samplerate) {
+               char *string;
+               string = g_strdup_printf (_("%d Hz"), samplerate);
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        "samplerate",
+                                                        string);
+               g_free (string);
+       } else {
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        "samplerate",
+                                                        C_("Sample rate", "N/A"));
+       }
+
+       channels = gst_discoverer_audio_info_get_channels (info);
+       if (channels) {
+               char *string;
+
+               if (channels > 2) {
+                       string = g_strdup_printf ("%s %d.1", _("Surround"), channels - 1);
+               } else if (channels == 1) {
+                       string = g_strdup (_("Mono"));
+               } else if (channels == 2) {
+                       string = g_strdup (_("Stereo"));
+               }
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        "channels",
+                                                        string);
+               g_free (string);
+       } else {
+               bacon_video_widget_properties_set_label (props->priv->props,
+                                                        "channels",
+                                                        C_("Number of audio channels", "N/A"));
+       }
+}
+
+static void
+discovered_cb (GstDiscoverer       *discoverer,
+              GstDiscovererInfo   *info,
+              GError              *error,
+              TotemPropertiesView *props)
+{
+       GList *video_streams, *audio_streams;
+       const GstTagList *taglist;
+       gboolean has_audio, has_video;
+       const char *label;
+        GstClockTime duration;
+        GstDiscovererStreamInfo *sinfo;
+
+       if (error) {
+               g_warning ("Couldn't get information about '%s': %s",
+                          gst_discoverer_info_get_uri (info),
+                          error->message);
+               return;
+       }
+
+       video_streams = gst_discoverer_info_get_video_streams (info);
+       has_video = (video_streams != NULL);
+       audio_streams = gst_discoverer_info_get_audio_streams (info);
+       has_audio = (audio_streams != NULL);
+
+       if (has_audio == has_video)
+               label = N_("Audio/Video");
+       else if (has_audio)
+               label = N_("Audio");
+       else
+               label = N_("Video");
+
+       gtk_label_set_text (GTK_LABEL (props->priv->label), _(label));
+
+       /* Widgets */
+       bacon_video_widget_properties_set_has_type (props->priv->props,
+                                                   has_video,
+                                                   has_audio);
+
+       /* General */
+        duration = gst_discoverer_info_get_duration (info);
+        bacon_video_widget_properties_set_duration (props->priv->props, duration / GST_SECOND * 1000);
+
+        sinfo = gst_discoverer_info_get_stream_info (info);
+        if (sinfo) {
+               set_codec (props, sinfo, "container");
+               gst_discoverer_stream_info_unref (sinfo);
+       }
+
+       taglist = gst_discoverer_info_get_tags (info);
+       update_general (props, taglist);
+
+       /* Video and Audio */
+       if (video_streams)
+               update_video (props, video_streams->data);
+       if (audio_streams)
+               update_audio (props, audio_streams->data);
+
+       gst_discoverer_stream_info_list_free (video_streams);
+       gst_discoverer_stream_info_list_free (audio_streams);
+}
+
+static void
+totem_properties_view_init (TotemPropertiesView *props)
+{
+       GError *err = NULL;
+
+       props->priv = g_new0 (TotemPropertiesViewPriv, 1);
+
+       props->priv->vbox = bacon_video_widget_properties_new ();
+       gtk_grid_attach (GTK_GRID (props), props->priv->vbox, 0, 0, 1, 1);
+       gtk_widget_show (GTK_WIDGET (props));
+
+       props->priv->props = BACON_VIDEO_WIDGET_PROPERTIES (props->priv->vbox);
+
+       props->priv->disco = gst_discoverer_new (GST_SECOND * 60, &err);
+       if (props->priv->disco == NULL) {
+               g_warning ("Could not create discoverer object: %s", err->message);
+               g_error_free (err);
+               return;
+       }
+       g_signal_connect (props->priv->disco, "discovered",
+                         G_CALLBACK (discovered_cb), props);
+}
+
+static void
+totem_properties_view_finalize (GObject *object)
+{
+       TotemPropertiesView *props;
+
+       props = TOTEM_PROPERTIES_VIEW (object);
+
+       if (props->priv != NULL) {
+               if (props->priv->disco) {
+                       g_signal_handlers_disconnect_by_func (props->priv->disco,
+                                                             discovered_cb,
+                                                             props);
+                       gst_discoverer_stop (props->priv->disco);
+                       g_clear_object (&props->priv->disco);
+               }
+               g_clear_object (&props->priv->label);
+               g_free (props->priv);
+       }
+       props->priv = NULL;
+
+       G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+totem_properties_view_set_location (TotemPropertiesView *props,
+                                   const char          *location)
+{
+       g_assert (TOTEM_IS_PROPERTIES_VIEW (props));
+
+       if (props->priv->disco)
+               gst_discoverer_stop (props->priv->disco);
+
+       bacon_video_widget_properties_reset (props->priv->props);
+
+       if (location != NULL && props->priv->disco != NULL) {
+               gst_discoverer_start (props->priv->disco);
+
+               if (gst_discoverer_discover_uri_async (props->priv->disco, location) == FALSE) {
+                       g_warning ("Couldn't add %s to list", location);
+                       return;
+               }
+       }
+}
+
+GtkWidget *
+totem_properties_view_new (const char *location, GtkWidget *label)
+{
+       TotemPropertiesView *self;
+
+       self = g_object_new (TOTEM_TYPE_PROPERTIES_VIEW, NULL);
+       g_object_ref (label);
+       self->priv->label = label;
+       totem_properties_view_set_location (self, location);
+
+       return GTK_WIDGET (self);
+}
diff --git a/extensions/audio-video-properties/totem-properties-view.h 
b/extensions/audio-video-properties/totem-properties-view.h
new file mode 100644
index 000000000..6b0a9f2a4
--- /dev/null
+++ b/extensions/audio-video-properties/totem-properties-view.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2003  Andrew Sobala <aes gnome org>
+ * Copyright (C) 2005  Bastien Nocera <hadess hadess net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission are above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ * Monday 7th February 2005: Christian Schaller: Add exception clause.
+ * See license_change file for details.
+ *
+ */
+
+#ifndef TOTEM_PROPERTIES_VIEW_H
+#define TOTEM_PROPERTIES_VIEW_H
+
+#include <gtk/gtk.h>
+
+#define TOTEM_TYPE_PROPERTIES_VIEW         (totem_properties_view_get_type ())
+#define TOTEM_PROPERTIES_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_CAST ((obj), TOTEM_TYPE_PROPERTIES_VIEW, 
TotemPropertiesView))
+#define TOTEM_PROPERTIES_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TOTEM_TYPE_PROPERTIES_VIEW, 
TotemPropertiesViewClass))
+#define TOTEM_IS_PROPERTIES_VIEW(obj)      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TOTEM_TYPE_PROPERTIES_VIEW))
+#define TOTEM_IS_PROPERTIES_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TOTEM_TYPE_PROPERTIES_VIEW))
+
+typedef struct TotemPropertiesViewPriv TotemPropertiesViewPriv;
+
+typedef struct {
+       GtkGrid parent;
+       TotemPropertiesViewPriv *priv;
+} TotemPropertiesView;
+
+typedef struct {
+       GtkGridClass parent;
+} TotemPropertiesViewClass;
+
+GType      totem_properties_view_get_type      (void);
+void       totem_properties_view_register_type (GTypeModule *module);
+
+GtkWidget *totem_properties_view_new           (const char *location,
+                                               GtkWidget  *label);
+
+#endif /* TOTEM_PROPERTIES_VIEW_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]