Index: src/backend/bacon-video-widget.h
===================================================================
--- src/backend/bacon-video-widget.h	(revision 5706)
+++ src/backend/bacon-video-widget.h	(working copy)
@@ -180,6 +180,12 @@
 						  const char *font);
 void bacon_video_widget_set_subtitle_encoding	 (BaconVideoWidget *bvw,
 						  const char *encoding);
+void bacon_video_widget_set_tempo		 (BaconVideoWidget *bvw,
+						  float tempo);
+float bacon_video_widget_get_tempo		 (BaconVideoWidget *bvw);
+void bacon_video_widget_set_pitch		 (BaconVideoWidget *bvw,
+						  float pitch);
+float bacon_video_widget_get_pitch		 (BaconVideoWidget *bvw);
 
 /* Metadata */
 typedef enum {
Index: src/backend/bacon-video-widget-gst-0.10.c
===================================================================
--- src/backend/bacon-video-widget-gst-0.10.c	(revision 5706)
+++ src/backend/bacon-video-widget-gst-0.10.c	(working copy)
@@ -114,7 +114,9 @@
   PROP_SEEKABLE,
   PROP_SHOWCURSOR,
   PROP_SHOW_VISUALS,
-  PROP_VOLUME
+  PROP_VOLUME,
+  PROP_TEMPO,
+  PROP_PITCH
 };
 
 static const gchar *video_props_str[4] = {
@@ -1006,6 +1008,14 @@
 	                           g_param_spec_double ("volume", NULL, NULL,
 	                                                0.0, 1.0, 0.0,
 	                                                G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_TEMPO,
+	                           g_param_spec_float ("tempo", NULL, NULL,
+	                                                0.1, 10.0, 1.0, /* TODO: how do the min/max compare to xine's? */
+	                                                G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_PITCH,
+	                           g_param_spec_float ("pitch", NULL, NULL,
+	                                                0.1, 10.0, 1.0, /* TODO: how do the min/max compare to xine's? */
+	                                                G_PARAM_READWRITE));
   g_object_class_install_property (object_class, PROP_SHOWCURSOR,
                                    g_param_spec_boolean ("showcursor", NULL,
                                                          NULL, FALSE,
@@ -1956,6 +1966,12 @@
     case PROP_VOLUME:
       bacon_video_widget_set_volume (bvw, g_value_get_double (value));
       break;
+    case PROP_TEMPO:
+      bacon_video_widget_set_tempo (bvw, g_value_get_float (value));
+      break;
+    case PROP_PITCH:
+      bacon_video_widget_set_pitch (bvw, g_value_get_float (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -1997,6 +2013,12 @@
     case PROP_VOLUME:
       g_value_set_double (value, bacon_video_widget_get_volume (bvw));
       break;
+    case PROP_TEMPO:
+      g_value_set_float (value, bacon_video_widget_get_tempo (bvw));
+      break;
+    case PROP_PITCH:
+      g_value_set_float (value, bacon_video_widget_get_pitch (bvw));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -3193,6 +3215,125 @@
   return vol;
 }
 
+static GstElement *
+insert_pitch_element_into_pipeline (BaconVideoWidget *bvw)
+{
+  GstBin *audiosinkbin;
+  GstPad *src_pad, *sink_pad;
+  GstElement *pitch_element;
+
+  /* Create the pitch element and insert it into the pipeline */
+  pitch_element = gst_element_factory_make ("pitch", "pitch");
+  if (!GST_IS_ELEMENT (pitch_element)) {
+    GST_DEBUG ("failed creating pitch element");
+    return NULL;
+  }
+
+  g_object_get (bvw->priv->play, "audio-sink", &audiosinkbin, NULL);
+  if (gst_bin_add (audiosinkbin, pitch_element) == FALSE) {
+    gst_object_unref (audiosinkbin);
+    gst_object_unref (pitch_element);
+    return NULL;
+  }
+
+  gst_object_unref (audiosinkbin);
+
+  /* Insert the new element into the pipeline */
+  src_pad = gst_element_get_static_pad (bvw->priv->audio_capsfilter, "src");
+  sink_pad = gst_pad_get_peer (src_pad);
+  gst_pad_unlink (src_pad, sink_pad);
+  gst_object_unref (src_pad);
+
+  src_pad = gst_element_get_pad (pitch_element, "src");
+  gst_pad_link (src_pad, sink_pad);
+  gst_object_unref (sink_pad);
+  gst_object_unref (src_pad);
+
+  gst_element_link_pads (bvw->priv->audio_capsfilter, "src",
+			 pitch_element, "sink");
+
+  gst_object_ref (pitch_element);
+  return pitch_element;
+}
+
+void
+bacon_video_widget_set_tempo (BaconVideoWidget *bvw, float tempo)
+{
+  GstElement *pitch_element;
+
+  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
+  g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play));
+
+  pitch_element = gst_bin_get_by_name (GST_BIN (bvw->priv->play), "pitch");
+
+  if (pitch_element == NULL)
+    pitch_element = insert_pitch_element_into_pipeline (bvw);
+  if (pitch_element == NULL)
+    return;
+
+  /* Change the tempo!  */
+  g_object_set (pitch_element, "tempo", tempo, NULL);
+  gst_object_unref (pitch_element);
+}
+
+float
+bacon_video_widget_get_tempo (BaconVideoWidget *bvw)
+{
+  GstElement *pitch_element;
+  gfloat tempo;
+
+  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
+  g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), 1.0);
+
+  pitch_element = gst_bin_get_by_name (GST_BIN (bvw->priv->play), "pitch");
+  if (pitch_element == NULL)
+    return 1.0;
+
+  g_object_get (pitch_element, "tempo", &tempo, NULL);
+  gst_object_unref (pitch_element);
+
+  return tempo;
+}
+
+void
+bacon_video_widget_set_pitch (BaconVideoWidget *bvw, float pitch)
+{
+  GstElement *pitch_element;
+
+  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
+  g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play));
+
+  pitch_element = gst_bin_get_by_name (GST_BIN (bvw->priv->play), "pitch");
+
+  if (pitch_element == NULL)
+    pitch_element = insert_pitch_element_into_pipeline (bvw);
+  if (pitch_element == NULL)
+    return;
+
+  /* Change the pitch!  */
+  g_object_set (pitch_element, "pitch", pitch, NULL);
+  gst_object_unref (pitch_element);
+}
+
+float
+bacon_video_widget_get_pitch (BaconVideoWidget *bvw)
+{
+  GstElement *pitch_element;
+  gfloat pitch;
+
+  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
+  g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), 1.0);
+
+  pitch_element = gst_bin_get_by_name (GST_BIN (bvw->priv->play), "pitch");
+  if (pitch_element == NULL)
+    return 1.0;
+
+  g_object_get (pitch_element, "pitch", &pitch, NULL);
+  gst_object_unref (pitch_element);
+
+  return pitch;
+}
+
 gboolean
 bacon_video_widget_fullscreen_mode_available (BaconVideoWidget *bvw,
                 TvOutType tvout) 
Index: src/plugins/pitch/pitch.totem-plugin.in
===================================================================
--- src/plugins/pitch/pitch.totem-plugin.in	(revision 0)
+++ src/plugins/pitch/pitch.totem-plugin.in	(revision 0)
@@ -0,0 +1,9 @@
+[Totem Plugin]
+Module=pitch
+IAge=1
+Builtin=false
+Name=Pitch
+Description=Allows the pitch and tempo of streams to be changed.
+Authors=Philip Withnall
+Copyright=Copyright © 2008 Philip Withnall
+Website=http://www.gnome.org/projects/totem/
Index: src/plugins/pitch/pitch.ui
===================================================================
--- src/plugins/pitch/pitch.ui	(revision 0)
+++ src/plugins/pitch/pitch.ui	(revision 0)
@@ -0,0 +1,112 @@
+<?xml version="1.0"?>
+<interface>
+	<object class="GtkAdjustment" id="totem_pitch_tempo_adjustment">
+		<property name="upper">10</property>
+		<property name="lower">0.1</property>
+		<property name="page_increment">1</property>
+		<property name="step_increment">0.5</property>
+		<property name="page_size">1</property>
+		<property name="value">1</property>
+	</object>
+	<object class="GtkAdjustment" id="totem_pitch_pitch_adjustment">
+		<property name="upper">10</property>
+		<property name="lower">0.1</property>
+		<property name="page_increment">1</property>
+		<property name="step_increment">0.5</property>
+		<property name="page_size">1</property>
+		<property name="value">1</property>
+	</object>
+	<object class="GtkDialog" id="totem_pitch_dialog">
+		<property name="title" translatable="yes">Change Pitch/Tempo</property>
+		<property name="border-width">5</property>
+		<property name="resizable">False</property>
+		<property name="window-position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+		<property name="type-hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+		<property name="has-separator">False</property>
+		<child internal-child="vbox">
+			<object class="GtkVBox" id="dialog-vbox1">
+				<property name="spacing">2</property>
+				<child>
+					<object class="GtkTable" id="table1">
+						<property name="n-rows">2</property>
+						<property name="n-columns">2</property>
+						<child>
+							<object class="GtkHScale" id="totem_pitch_tempo_scale">
+								<property name="adjustment">totem_pitch_tempo_adjustment</property>
+							</object>
+							<packing>
+								<property name="left-attach">1</property>
+								<property name="right-attach">2</property>
+								<property name="top-attach">1</property>
+								<property name="bottom-attach">2</property>
+							</packing>
+						</child>
+						<child>
+							<object class="GtkHScale" id="totem_pitch_pitch_scale">
+								<property name="adjustment">totem_pitch_pitch_adjustment</property>
+							</object>
+							<packing>
+								<property name="left-attach">1</property>
+								<property name="right-attach">2</property>
+							</packing>
+						</child>
+						<child>
+							<object class="GtkLabel" id="label2">
+								<property name="xalign">1</property>
+								<property name="label" translatable="yes">&lt;b&gt;Tempo&lt;/b&gt;</property>
+								<property name="use-markup">True</property>
+							</object>
+							<packing>
+								<property name="top-attach">1</property>
+								<property name="bottom-attach">2</property>
+								<property name="x-options">GTK_FILL</property>
+								<property name="x-padding">5</property>
+							</packing>
+						</child>
+						<child>
+							<object class="GtkLabel" id="label1">
+								<property name="xalign">1</property>
+								<property name="label" translatable="yes">&lt;b&gt;Pitch&lt;/b&gt;</property>
+								<property name="use-markup">True</property>
+							</object>
+							<packing>
+								<property name="x-options">GTK_FILL</property>
+								<property name="x-padding">5</property>
+							</packing>
+						</child>
+					</object>
+					<packing>
+						<property name="expand">False</property>
+						<property name="padding">5</property>
+					</packing>
+				</child>
+				<child internal-child="action_area">
+					<object class="GtkHButtonBox" id="dialog-action_area1">
+						<property name="layout-style">GTK_BUTTONBOX_END</property>
+						<child>
+							<object class="GtkButton" id="totem_pitch_cancel_button">
+								<property name="label" translatable="yes">gtk-cancel</property>
+								<property name="use-stock">True</property>
+							</object>
+						</child>
+						<child>
+							<object class="GtkButton" id="totem_pitch_ok_button">
+								<property name="receives-default">True</property>
+								<property name="label" translatable="yes">gtk-ok</property>
+								<property name="use-stock">True</property>
+							</object>
+						</child>
+					</object>
+					<packing>
+						<property name="expand">False</property>
+						<property name="pack-type">GTK_PACK_END</property>
+					</packing>
+				</child>
+			</object>
+		</child>
+		<action-widgets>
+			<action-widget response="-6">totem_pitch_cancel_button</action-widget><!-- GTK_RESPONSE_CANCEL -->
+			<action-widget response="-5">totem_pitch_ok_button</action-widget><!-- GTK_RESPONSE_OK -->
+		</action-widgets>
+	</object>
+</interface>
Index: src/plugins/pitch/totem-pitch.h
===================================================================
--- src/plugins/pitch/totem-pitch.h	(revision 0)
+++ src/plugins/pitch/totem-pitch.h	(revision 0)
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Copyright (C) 2008 Philip Withnall <philip@tecnocode.co.uk>
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  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 excemption clause.
+ * See license_change file for details.
+ *
+ * Author: Bastien Nocera <hadess@hadess.net>, Philip Withnall <philip@tecnocode.co.uk>
+ */
+
+#ifndef TOTEM_PITCH_H
+#define TOTEM_PITCH_H
+
+#include <glib.h>
+
+#include "totem.h"
+#include "totem-plugin.h"
+
+G_BEGIN_DECLS
+
+#define TOTEM_TYPE_PITCH_PLUGIN			(totem_pitch_plugin_get_type ())
+#define TOTEM_PITCH_PLUGIN(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), TOTEM_TYPE_PITCH_PLUGIN, TotemPitchPlugin))
+#define TOTEM_PITCH_PLUGIN_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), TOTEM_TYPE_PITCH_PLUGIN, TotemPitchPluginClass))
+#define TOTEM_IS_PITCH_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), TOTEM_TYPE_PITCH_PLUGIN))
+#define TOTEM_IS_PITCH_PLUGIN_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), TOTEM_TYPE_PITCH_PLUGIN))
+#define TOTEM_PITCH_PLUGIN_GET_CLASS(o)		(G_TYPE_INSTANCE_GET_CLASS ((o), TOTEM_TYPE_PITCH_PLUGIN, TotemPitchPluginClass))
+
+typedef struct TotemPitchPluginPrivate         TotemPitchPluginPrivate;
+
+typedef struct
+{
+	TotemPlugin parent;
+	TotemPitchPluginPrivate *priv;
+} TotemPitchPlugin;
+
+typedef struct
+{
+	TotemPluginClass parent_class;
+} TotemPitchPluginClass;
+
+GType totem_pitch_plugin_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* TOTEM_PITCH_H */
Index: src/plugins/pitch/Makefile.am
===================================================================
--- src/plugins/pitch/Makefile.am	(revision 0)
+++ src/plugins/pitch/Makefile.am	(revision 0)
@@ -0,0 +1,48 @@
+modules_flags = -export_dynamic -avoid-version -module
+
+plugindir = $(PLUGINDIR)/pitch
+uidir = $(plugindir)
+plugin_LTLIBRARIES = libpitch.la
+
+plugin_in_files = pitch.totem-plugin.in
+
+%.totem-plugin: %.totem-plugin.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.totem-plugin.in=.totem-plugin)
+ui_DATA = pitch.ui
+
+common_defines = \
+	-D_REENTRANT					\
+	-DDBUS_API_SUBJECT_TO_CHANGE			\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"	\
+	-DGCONF_PREFIX=\""/apps/totem"\"		\
+	-DDATADIR=\""$(datadir)"\"			\
+	-DLIBEXECDIR=\""$(libexecdir)"\"		\
+	-DBINDIR=\""$(bindir)"\"			\
+	-DTOTEM_PLUGIN_DIR=\""$(libdir)/totem/plugins"\"\
+	$(DISABLE_DEPRECATED)
+
+libpitch_la_SOURCES = \
+	totem-pitch.c		\
+	totem-pitch.h
+libpitch_la_LDFLAGS = $(modules_flags)
+libpitch_la_CPPFLAGS = \
+	$(common_defines)		\
+	-I$(top_srcdir)/src/backend	\
+	-I$(top_srcdir)/plparse
+
+libpitch_la_CFLAGS = 			\
+	$(EXTRA_GNOME_CFLAGS)		\
+	$(WARN_CFLAGS)			\
+	$(DBUS_CFLAGS)			\
+	$(AM_CFLAGS)			\
+	-I$(top_srcdir)/		\
+	-I$(top_srcdir)/src		\
+	-I$(top_srcdir)/src/backend	\
+	-I$(top_srcdir)/src/plugins	\
+	-I$(srcdir)/
+
+EXTRA_DIST = $(plugin_in_files) $(ui_DATA)
+
+CLEANFILES = $(plugin_DATA) $(BUILT_SOURCES)
+DISTCLEANFILES = $(plugin_DATA)
Index: src/plugins/pitch/totem-pitch.c
===================================================================
--- src/plugins/pitch/totem-pitch.c	(revision 0)
+++ src/plugins/pitch/totem-pitch.c	(revision 0)
@@ -0,0 +1,186 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Copyright (C) 2008 Philip Withnall <philip@tecnocode.co.uk>
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  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 excemption clause.
+ * See license_change file for details.
+ *
+ * Author: Philip Withnall <philip@tecnocode.co.uk>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <string.h>
+
+#include "totem-pitch.h"
+#include "totem.h"
+#include "bacon-video-widget.h"
+
+struct TotemPitchPluginPrivate
+{
+	Totem		*totem;
+	guint		ui_merge_id;
+	GtkActionGroup	*action_group;
+	GtkAdjustment	*pitch_adjustment;
+	GtkAdjustment	*tempo_adjustment;
+	GtkBuilder	*xml;
+};
+
+G_MODULE_EXPORT GType register_totem_plugin		(GTypeModule *module);
+
+static void totem_pitch_plugin_init			(TotemPitchPlugin *plugin);
+static void totem_pitch_plugin_finalize			(GObject *object);
+static gboolean impl_activate				(TotemPlugin *plugin, TotemObject *totem, GError **error);
+static void impl_deactivate				(TotemPlugin *plugin, TotemObject *totem);
+
+TOTEM_PLUGIN_REGISTER (TotemPitchPlugin, totem_pitch_plugin);
+
+static void
+totem_pitch_plugin_class_init (TotemPitchPluginClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	TotemPluginClass *plugin_class = TOTEM_PLUGIN_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (TotemPitchPluginPrivate));
+
+	object_class->finalize = totem_pitch_plugin_finalize;
+
+	plugin_class->activate = impl_activate;
+	plugin_class->deactivate = impl_deactivate;
+}
+
+static void
+totem_pitch_plugin_init (TotemPitchPlugin *plugin)
+{
+	plugin->priv = G_TYPE_INSTANCE_GET_PRIVATE (plugin, TOTEM_TYPE_PITCH_PLUGIN, TotemPitchPluginPrivate);
+}
+
+static void
+totem_pitch_plugin_finalize (GObject *object)
+{
+	GtkWidget *dialog;
+	TotemPitchPlugin *plugin = TOTEM_PITCH_PLUGIN (object);
+
+	dialog = GTK_WIDGET (gtk_builder_get_object (plugin->priv->xml, "totem_pitch_dialog"));
+	gtk_widget_destroy (dialog);
+	g_object_unref (plugin->priv->xml);
+
+	G_OBJECT_CLASS (totem_pitch_plugin_parent_class)->finalize (object);
+}
+
+static void
+run_dialogue (TotemPitchPlugin *plugin)
+{
+	GtkWidget *dialog;
+
+	if (plugin->priv->xml == NULL) {
+		plugin->priv->xml = totem_plugin_load_interface (TOTEM_PLUGIN (plugin), "pitch.ui", TRUE, NULL, plugin);
+
+		if (plugin->priv->xml == NULL)
+			return;
+
+		plugin->priv->pitch_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (plugin->priv->xml, "totem_pitch_pitch_adjustment"));
+		plugin->priv->tempo_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (plugin->priv->xml, "totem_pitch_tempo_adjustment"));
+	}
+
+	/* Run the dialogue */
+	dialog = GTK_WIDGET (gtk_builder_get_object (plugin->priv->xml, "totem_pitch_dialog"));
+	gtk_widget_show_all (dialog);
+	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+		/* Change the pitch/tempo */
+		BaconVideoWidget *bvw;
+
+		bvw = BACON_VIDEO_WIDGET (totem_get_video_widget (plugin->priv->totem));
+		bacon_video_widget_set_pitch (bvw, gtk_adjustment_get_value (plugin->priv->pitch_adjustment));
+		bacon_video_widget_set_tempo (bvw, gtk_adjustment_get_value (plugin->priv->tempo_adjustment));
+		g_object_unref (bvw);
+	}
+	gtk_widget_hide_all (dialog);
+}
+
+static void
+pitch_action_cb (GtkAction *action, TotemPitchPlugin *plugin)
+{
+	run_dialogue (plugin);
+}
+
+static gboolean
+impl_activate (TotemPlugin *plugin, TotemObject *totem, GError **error)
+{
+	GtkUIManager *manager;
+	BaconVideoWidget *bvw;
+	TotemPitchPlugin *pi = TOTEM_PITCH_PLUGIN (plugin);
+	TotemPitchPluginPrivate *priv = pi->priv;
+
+	char *builder_path;
+	const GtkActionEntry menu_entries[] = {
+		{ "pitch", "", N_("Change _Pitch/Tempo"), "", N_("Change the stream's pitch or tempo."), G_CALLBACK (pitch_action_cb) }
+	};
+
+	/* Ensure the UI file exists */
+	builder_path = totem_plugin_find_file (TOTEM_PLUGIN (plugin), "pitch.ui");
+	if (builder_path == NULL) {
+		g_set_error (error, TOTEM_PLUGIN_ERROR, TOTEM_PLUGIN_ERROR_ACTIVATION,
+				_("Could not load the \"Pitch\" dialog interface."));
+		return FALSE;
+	}
+	g_free (builder_path);
+
+	/* Modify the GStreamer pipeline */
+	bvw = BACON_VIDEO_WIDGET (totem_get_video_widget (totem));
+	bacon_video_widget_set_tempo (bvw, 1.0);
+	g_object_unref (bvw);
+
+	/* Install the menu */
+	priv->action_group = gtk_action_group_new ("pitch_group");
+	gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (priv->action_group, menu_entries,
+				G_N_ELEMENTS (menu_entries), pi);
+
+	manager = totem_get_ui_manager (totem);
+
+	gtk_ui_manager_insert_action_group (manager, priv->action_group, -1);
+	g_object_unref (priv->action_group);
+
+	priv->ui_merge_id = gtk_ui_manager_new_merge_id (manager);
+	gtk_ui_manager_add_ui (manager, priv->ui_merge_id,
+			       "/ui/tmw-menubar/go/skip-backwards", "pitch",
+			       "pitch", GTK_UI_MANAGER_AUTO, FALSE);
+
+	priv->totem = totem;
+
+	return TRUE;
+}
+
+static void
+impl_deactivate	(TotemPlugin *plugin, TotemObject *totem)
+{
+	GtkUIManager *manager;
+	TotemPitchPluginPrivate *priv = TOTEM_PITCH_PLUGIN (plugin)->priv;
+
+	/* Remove the menu */
+	manager = totem_get_ui_manager (totem);
+	gtk_ui_manager_remove_ui (manager, priv->ui_merge_id);
+	gtk_ui_manager_remove_action_group (manager, priv->action_group);
+}
