diff -urpNB gst-plugins-good.orig/docs/plugins/gst-plugins-good-plugins-docs.sgml gst-plugins-good/docs/plugins/gst-plugins-good-plugins-docs.sgml
--- gst-plugins-good.orig/docs/plugins/gst-plugins-good-plugins-docs.sgml	2011-01-20 23:28:18.000000000 +0300
+++ gst-plugins-good/docs/plugins/gst-plugins-good-plugins-docs.sgml	2011-01-20 22:13:48.000000000 +0300
@@ -153,6 +153,7 @@
     <xi:include href="xml/element-udpsink.xml" />
     <xi:include href="xml/element-v4l2src.xml" />
     <xi:include href="xml/element-v4l2sink.xml" />
+    <xi:include href="xml/element-v4l2radio.xml" />
     <xi:include href="xml/element-vertigotv.xml" />
     <xi:include href="xml/element-videobalance.xml" />
     <xi:include href="xml/element-videobox.xml" />
diff -urpNB gst-plugins-good.orig/docs/plugins/gst-plugins-good-plugins-sections.txt gst-plugins-good/docs/plugins/gst-plugins-good-plugins-sections.txt
--- gst-plugins-good.orig/docs/plugins/gst-plugins-good-plugins-sections.txt	2011-01-20 23:28:18.000000000 +0300
+++ gst-plugins-good/docs/plugins/gst-plugins-good-plugins-sections.txt	2011-01-20 22:14:36.000000000 +0300
@@ -2037,6 +2037,20 @@ gst_v4l2sink_get_type
 </SECTION>
 
 <SECTION>
+<FILE>element-v4l2radio</FILE>
+<TITLE>v4l2radio</TITLE>
+GstV4l2Radio
+<SUBSECTION Standard>
+GstV4l2RadioClass
+GST_V4L2RADIO
+GST_IS_V4L2RADIO
+GST_TYPE_V4L2RADIO
+GST_V4L2RADIO_CLASS
+GST_IS_V4L2RADIO_CLASS
+gst_v4l2radio_get_type
+</SECTION>
+
+<SECTION>
 <FILE>element-waveformsink</FILE>
 <TITLE>waveformsink</TITLE>
 GstWaveFormSink
diff -urpNB gst-plugins-good.orig/docs/plugins/inspect/plugin-video4linux2.xml gst-plugins-good/docs/plugins/inspect/plugin-video4linux2.xml
--- gst-plugins-good.orig/docs/plugins/inspect/plugin-video4linux2.xml	2011-01-20 23:28:18.000000000 +0300
+++ gst-plugins-good/docs/plugins/inspect/plugin-video4linux2.xml	2011-01-20 23:04:10.000000000 +0300
@@ -24,5 +24,12 @@
         </caps>
       </pads>
     </element>
+    <element>
+      <name>v4l2radio</name>
+      <longname>Radio (video4linux2) Tuner</longname>
+      <class>Tuner</class>
+      <description>Controls a Video4Linux2 radio device</description>
+      <author>Alexey Chernov &lt;4ernov@gmail.com&gt;</author>
+    </element>
   </elements>
-</plugin>
\ В конце файла нет новой строки
+</plugin>
diff -urpNB gst-plugins-good.orig/docs/plugins/Makefile.am gst-plugins-good/docs/plugins/Makefile.am
--- gst-plugins-good.orig/docs/plugins/Makefile.am	2011-01-20 23:28:18.000000000 +0300
+++ gst-plugins-good/docs/plugins/Makefile.am	2011-01-20 22:13:11.000000000 +0300
@@ -228,6 +228,7 @@ EXTRA_HFILES = \
 	$(top_srcdir)/sys/osxvideo/osxvideosink.h \
 	$(top_srcdir)/sys/v4l2/gstv4l2src.h \
 	$(top_srcdir)/sys/v4l2/gstv4l2sink.h \
+	$(top_srcdir)/sys/v4l2/gstv4l2radio.h \
 	$(top_srcdir)/sys/waveform/gstwaveformsink.h \
 	$(top_srcdir)/sys/ximage/gstximagesrc.h
 
diff -urpNB gst-plugins-good.orig/sys/v4l2/gstv4l2.c gst-plugins-good/sys/v4l2/gstv4l2.c
--- gst-plugins-good.orig/sys/v4l2/gstv4l2.c	2011-01-20 23:28:18.000000000 +0300
+++ gst-plugins-good/sys/v4l2/gstv4l2.c	2011-01-20 22:18:45.000000000 +0300
@@ -35,6 +35,7 @@
 #ifdef HAVE_EXPERIMENTAL
 #include "gstv4l2sink.h"
 #endif
+#include "gstv4l2radio.h"
 /* #include "gstv4l2jpegsrc.h" */
 /* #include "gstv4l2mjpegsrc.h" */
 /* #include "gstv4l2mjpegsink.h" */
@@ -58,6 +59,8 @@ plugin_init (GstPlugin * plugin)
       !gst_element_register (plugin, "v4l2sink", GST_RANK_NONE,
           GST_TYPE_V4L2SINK) ||
 #endif
+      !gst_element_register (plugin, "v4l2radio", GST_RANK_NONE,
+          GST_TYPE_V4L2RADIO) ||
       /*       !gst_element_register (plugin, "v4l2jpegsrc", */
       /*           GST_RANK_NONE, GST_TYPE_V4L2JPEGSRC) || */
       /*       !gst_element_register (plugin, "v4l2mjpegsrc", */
diff -urpNB gst-plugins-good.orig/sys/v4l2/gstv4l2radio.c gst-plugins-good/sys/v4l2/gstv4l2radio.c
--- gst-plugins-good.orig/sys/v4l2/gstv4l2radio.c	1970-01-01 03:00:00.000000000 +0300
+++ gst-plugins-good/sys/v4l2/gstv4l2radio.c	2011-01-20 23:21:59.000000000 +0300
@@ -0,0 +1,445 @@
+/* GStreamer
+ * 
+ * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
+ * 
+ * gstv4l2radio.c - V4L2 radio tuner element
+ *
+ * This 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.
+ *
+ * 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+/**
+ * SECTION:element-v4l2radio
+ *
+ * v4l2radio can be used to control radio device
+ * and to tune it to different radiostations.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch v4l2radio device=/dev/radio0 frequency=101200000
+ * gst-launch alsasrc device=hw:1 ! audioconvert ! audioresample ! alsasink
+ * ]|
+ * First pipeline tunes the radio device /dev/radio0 to station 101.2 MHz,
+ * second pipeline connects digital audio out (hw:1) to default sound card.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gstv4l2tuner.h"
+#include "gstv4l2radio.h"
+#include "v4l2_calls.h"
+#include "v4l2radio_calls.h"
+
+GST_DEBUG_CATEGORY (v4l2radio_debug);
+#define GST_CAT_DEFAULT v4l2radio_debug
+
+#define DEFAULT_PROP_DEVICE "/dev/radio0"
+#define MIN_FREQUENCY		 87500000
+#define DEFAULT_FREQUENCY	100000000
+#define MAX_FREQUENCY		108000000
+
+enum
+{
+  ARG_0,
+  ARG_DEVICE,
+  ARG_FREQUENCY
+};
+
+GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2RadioClass, gst_v4l2radio);
+GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Radio, gst_v4l2radio);
+
+static void gst_v4l2radio_uri_handler_init (gpointer g_iface,
+    gpointer iface_data);
+
+static gboolean
+gst_v4l2radio_interface_supported (GstImplementsInterface * iface,
+    GType iface_type)
+{
+  if (iface_type == GST_TYPE_TUNER)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+static void
+gst_v4l2radio_implements_interface_init (GstImplementsInterfaceClass * iface)
+{
+  iface->supported = gst_v4l2radio_interface_supported;
+}
+
+static void
+gst_v4l2radio_tuner_interface_reinit (GstTunerClass * iface)
+{
+  gst_v4l2radio_tuner_interface_init (iface);
+}
+
+static void
+gst_v4l2radio_interfaces (GType type)
+{
+  static const GInterfaceInfo urihandler_info = {
+    (GInterfaceInitFunc) gst_v4l2radio_uri_handler_init,
+    NULL,
+    NULL
+  };
+
+  static const GInterfaceInfo implements_interface_info = {
+    (GInterfaceInitFunc) gst_v4l2radio_implements_interface_init,
+    NULL,
+    NULL,
+  };
+
+  static const GInterfaceInfo propertyprobe_info = {
+    (GInterfaceInitFunc) gst_v4l2radio_property_probe_interface_init,
+    NULL,
+    NULL,
+  };
+
+  static const GInterfaceInfo tuner_interface_info = {
+    (GInterfaceInitFunc) gst_v4l2radio_tuner_interface_reinit,
+    NULL,
+    NULL,
+  };
+
+  g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
+  g_type_add_interface_static (type,
+      GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info);
+
+  g_type_add_interface_static (type, GST_TYPE_TUNER, &tuner_interface_info);
+
+  g_type_add_interface_static (type,
+      GST_TYPE_PROPERTY_PROBE, &propertyprobe_info);
+}
+
+GST_BOILERPLATE_FULL (GstV4l2Radio, gst_v4l2radio, GstElement, GST_TYPE_ELEMENT,
+    gst_v4l2radio_interfaces);
+
+static void gst_v4l2radio_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_v4l2radio_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_v4l2radio_finalize (GstV4l2Radio * radio);
+static void gst_v4l2radio_dispose (GObject * object);
+static GstStateChangeReturn gst_v4l2radio_change_state (GstElement * element,
+    GstStateChange transition);
+
+static void
+gst_v4l2radio_base_init (gpointer gclass)
+{
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (gclass);
+  GstV4l2RadioClass *gstv4l2radio_class = GST_V4L2RADIO_CLASS (gclass);
+
+  GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0,
+      "V4l2 radio element");
+
+  gstv4l2radio_class->v4l2_class_devices = NULL;
+
+  gst_element_class_set_details_simple (gstelement_class,
+      "Radio (video4linux2) Tuner",
+      "Tuner",
+      "Controls a Video4Linux2 radio device",
+      "Alexey Chernov <4ernov@gmail.com>");
+}
+
+static void
+gst_v4l2radio_class_init (GstV4l2RadioClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->set_property = gst_v4l2radio_set_property;
+  gobject_class->get_property = gst_v4l2radio_get_property;
+
+  g_object_class_install_property (gobject_class, ARG_DEVICE,
+      g_param_spec_string ("device", "Radio device location",
+          "Video4Linux2 radio device location",
+          DEFAULT_PROP_DEVICE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, ARG_FREQUENCY,
+      g_param_spec_int ("frequency", "Station frequency",
+          "Station frequency in Hz",
+          MIN_FREQUENCY, MAX_FREQUENCY, DEFAULT_FREQUENCY, G_PARAM_READWRITE));
+
+  gobject_class->dispose = gst_v4l2radio_dispose;
+  gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize;
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_v4l2radio_change_state);
+
+}
+
+static void
+gst_v4l2radio_init (GstV4l2Radio * filter, GstV4l2RadioClass * gclass)
+{
+  filter->v4l2object = gst_v4l2_object_new (GST_ELEMENT (filter),
+      V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE,
+      gst_v4l2radio_get_input, gst_v4l2radio_set_input, NULL);
+
+  filter->v4l2object->frequency = DEFAULT_FREQUENCY;
+  filter->v4l2object->videodev = g_strdup (DEFAULT_PROP_DEVICE);
+}
+
+static void
+gst_v4l2radio_dispose (GObject * object)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (object);
+  gst_v4l2_close (radio->v4l2object);
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_v4l2radio_finalize (GstV4l2Radio * radio)
+{
+  gst_v4l2_object_destroy (radio->v4l2object);
+  G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (radio));
+}
+
+static gboolean
+gst_v4l2radio_open (GstV4l2Radio * radio)
+{
+  GstV4l2Object *v4l2object;
+
+  v4l2object = radio->v4l2object;
+  if (gst_v4l2_open (v4l2object))
+    return gst_v4l2radio_fill_channel_list (radio);
+  else
+    return FALSE;
+}
+
+static void
+gst_v4l2radio_set_defaults (GstV4l2Radio * radio)
+{
+  GstV4l2Object *v4l2object;
+  GstTunerChannel *channel = NULL;
+  GstTuner *tuner;
+
+  v4l2object = radio->v4l2object;
+
+  if (!GST_IS_TUNER (v4l2object->element))
+    return;
+
+  tuner = GST_TUNER (v4l2object->element);
+
+  if (v4l2object->channel)
+    channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
+  if (channel) {
+    gst_tuner_set_channel (tuner, channel);
+  } else {
+    channel =
+        GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER
+            (v4l2object->element)));
+    if (channel) {
+      g_free (v4l2object->channel);
+      v4l2object->channel = g_strdup (channel->label);
+      gst_tuner_channel_changed (tuner, channel);
+    }
+  }
+
+  if (channel
+      && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
+    if (v4l2object->frequency != 0) {
+      gst_tuner_set_frequency (tuner, channel, v4l2object->frequency);
+    } else {
+      v4l2object->frequency = gst_tuner_get_frequency (tuner, channel);
+      if (v4l2object->frequency == 0) {
+        /* guess */
+        gst_tuner_set_frequency (tuner, channel, MIN_FREQUENCY);
+      } else {
+      }
+    }
+  }
+}
+
+static gboolean
+gst_v4l2radio_start (GstV4l2Radio * radio)
+{
+  if (!gst_v4l2radio_open (radio))
+    return FALSE;
+
+  gst_v4l2radio_set_defaults (radio);
+
+  return TRUE;
+}
+
+static gboolean
+gst_v4l2radio_stop (GstV4l2Radio * radio)
+{
+  if (!gst_v4l2_object_stop (radio->v4l2object))
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstStateChangeReturn
+gst_v4l2radio_change_state (GstElement * element, GstStateChange transition)
+{
+  GstV4l2Radio *radio;
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  radio = GST_V4L2RADIO (element);
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      /*start radio */
+      if (!gst_v4l2radio_start (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      /*unmute radio */
+      if (!gst_v4l2radio_set_unmute (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      /*mute radio */
+      if (!gst_v4l2radio_set_mute (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      /*stop radio */
+      if (!gst_v4l2radio_stop (radio))
+        ret = GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_v4l2radio_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (object);
+  gint frequency;
+  switch (prop_id) {
+    case ARG_DEVICE:
+      radio->v4l2object->videodev =
+          g_strdup ((gchar *) g_value_get_string (value));
+      break;
+    case ARG_FREQUENCY:
+      frequency = g_value_get_int (value);
+      if (frequency >= MIN_FREQUENCY && frequency <= MAX_FREQUENCY) {
+        radio->v4l2object->frequency = frequency;
+        gst_v4l2_set_frequency (radio->v4l2object, 0,
+            radio->v4l2object->frequency);
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_v4l2radio_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (object);
+
+  switch (prop_id) {
+    case ARG_DEVICE:
+      g_value_set_string (value, radio->v4l2object->videodev);
+      break;
+    case ARG_FREQUENCY:
+      if (gst_v4l2_get_frequency (radio->v4l2object,
+              0, &(radio->v4l2object->frequency)))
+        g_value_set_int (value, radio->v4l2object->frequency);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/* GstURIHandler interface */
+static GstURIType
+gst_v4l2radio_uri_get_type (void)
+{
+  return GST_URI_SRC;
+}
+
+static gchar **
+gst_v4l2radio_uri_get_protocols (void)
+{
+  static gchar *protocols[] = { (char *) "radio", NULL };
+  return protocols;
+}
+
+static const gchar *
+gst_v4l2radio_uri_get_uri (GstURIHandler * handler)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (handler);
+
+  if (radio->v4l2object->videodev != NULL) {
+    if (gst_v4l2_get_frequency (radio->v4l2object,
+            0, &(radio->v4l2object->frequency))) {
+      gchar uri[20];
+      gchar freq[6];
+      g_ascii_formatd (freq, 6, "%4.1f", radio->v4l2object->frequency / 1e6);
+      g_snprintf (uri, sizeof (uri), "radio://%s", freq);
+      return g_intern_string (uri);
+    }
+  }
+
+  return "radio://";
+}
+
+static gboolean
+gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+  GstV4l2Radio *radio = GST_V4L2RADIO (handler);
+  gdouble dfreq;
+  gint ifreq;
+  const gchar *freq;
+  gchar *end;
+
+  if (strcmp (uri, "radio://") != 0) {
+    freq = uri + 8;
+
+    dfreq = g_ascii_strtod (freq, &end);
+
+    if (errno || strlen (end))
+      goto uri_failed;
+
+    ifreq = dfreq * 1e6;
+    g_object_set (radio, "frequency", ifreq, NULL);
+
+  } else
+    goto uri_failed;
+
+  return TRUE;
+
+uri_failed:
+  return FALSE;
+}
+
+static void
+gst_v4l2radio_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+  GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+  iface->get_type = gst_v4l2radio_uri_get_type;
+  iface->get_protocols = gst_v4l2radio_uri_get_protocols;
+  iface->get_uri = gst_v4l2radio_uri_get_uri;
+  iface->set_uri = gst_v4l2radio_uri_set_uri;
+}
diff -urpNB gst-plugins-good.orig/sys/v4l2/gstv4l2radio.h gst-plugins-good/sys/v4l2/gstv4l2radio.h
--- gst-plugins-good.orig/sys/v4l2/gstv4l2radio.h	1970-01-01 03:00:00.000000000 +0300
+++ gst-plugins-good/sys/v4l2/gstv4l2radio.h	2011-01-20 23:21:59.000000000 +0300
@@ -0,0 +1,70 @@
+/* GStreamer
+ * 
+ * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
+ * 
+ * gstv4l2radio.h - V4L2 radio tuner element
+ *
+ * This 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.
+ *
+ * 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+#ifndef __GST_V4L2RADIO_H__
+#define __GST_V4L2RADIO_H__
+
+#include "gstv4l2object.h"
+
+GST_DEBUG_CATEGORY_EXTERN (v4l2radio_debug);
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2RADIO \
+  (gst_v4l2radio_get_type())
+#define GST_V4L2RADIO(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2RADIO,GstV4l2Radio))
+#define GST_V4L2RADIO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2RADIO,GstV4l2RadioClass))
+#define GST_IS_V4L2RADIO(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2RADIO))
+#define GST_IS_V4L2RADIO_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2RADIO))
+
+typedef struct _GstV4l2Radio      GstV4l2Radio;
+typedef struct _GstV4l2RadioClass GstV4l2RadioClass;
+
+/**
+ * GstV4l2Radio:
+ * @v4l2object: parent #GstV4l2Object.
+ *
+ */
+struct _GstV4l2Radio
+{
+  GstElement element;
+  
+  /*< private >*/
+  GstV4l2Object * v4l2object;
+};
+
+struct _GstV4l2RadioClass
+{
+  GstElementClass parent_class;
+  
+  GList *v4l2_class_devices;
+};
+
+GType gst_v4l2radio_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2RADIO_H__ */
diff -urpNB gst-plugins-good.orig/sys/v4l2/Makefile.am gst-plugins-good/sys/v4l2/Makefile.am
--- gst-plugins-good.orig/sys/v4l2/Makefile.am	2011-01-20 23:28:18.000000000 +0300
+++ gst-plugins-good/sys/v4l2/Makefile.am	2011-01-20 22:22:18.000000000 +0300
@@ -13,10 +13,12 @@ libgstvideo4linux2_la_SOURCES = gstv4l2.
 				gstv4l2object.c \
 				gstv4l2bufferpool.c \
 				gstv4l2src.c \
+				gstv4l2radio.c \
 				gstv4l2tuner.c \
 				gstv4l2vidorient.c \
 				v4l2_calls.c \
 				v4l2src_calls.c \
+				v4l2radio_calls.c \
 				$(xv_source)
 
 if BUILD_EXPERIMENTAL
@@ -51,8 +53,10 @@ noinst_HEADERS = \
 	gstv4l2object.h \
 	gstv4l2sink.h \
 	gstv4l2src.h \
+	gstv4l2radio.h \
 	gstv4l2tuner.h \
 	gstv4l2vidorient.h \
 	gstv4l2xoverlay.h \
 	v4l2_calls.h \
-	v4l2src_calls.h
+	v4l2src_calls.h \
+	v4l2radio_calls.h
diff -urpNB gst-plugins-good.orig/sys/v4l2/v4l2radio_calls.c gst-plugins-good/sys/v4l2/v4l2radio_calls.c
--- gst-plugins-good.orig/sys/v4l2/v4l2radio_calls.c	1970-01-01 03:00:00.000000000 +0300
+++ gst-plugins-good/sys/v4l2/v4l2radio_calls.c	2011-01-20 23:22:15.000000000 +0300
@@ -0,0 +1,223 @@
+/* GStreamer
+ * 
+ * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
+ * 
+ * v4l2radio_calls.c - additional system calls for radio support
+ *
+ * This 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.
+ *
+ * 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+#include "gst/gst-i18n-plugin.h"
+
+#include "gstv4l2object.h"
+#include "gstv4l2tuner.h"
+#include "v4l2radio_calls.h"
+#include "v4l2_calls.h"
+
+gboolean
+gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio)
+{
+  int res;
+  struct v4l2_tuner vtun;
+  struct v4l2_capability vc;
+  GstV4l2TunerChannel *v4l2channel;
+  GstTunerChannel *channel;
+
+  GstElement *e;
+
+  GstV4l2Object *v4l2object;
+
+  e = GST_ELEMENT (radio);
+  v4l2object = radio->v4l2object;
+
+  GST_DEBUG_OBJECT (e, "getting audio enumeration");
+  GST_V4L2_CHECK_OPEN (v4l2object);
+
+  GST_DEBUG_OBJECT (e, "  audio input");
+
+  memset (&vc, 0, sizeof (vc));
+
+  res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc);
+  if (res < 0)
+    goto caps_failed;
+
+  if (!(vc.capabilities & V4L2_CAP_TUNER))
+    goto not_a_tuner;
+
+  /* getting audio input */
+  memset (&vtun, 0, sizeof (vtun));
+  vtun.index = 0;
+
+  res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun);
+  if (res < 0)
+    goto tuner_failed;
+
+  GST_LOG_OBJECT (e, "   index:     %d", vtun.index);
+  GST_LOG_OBJECT (e, "   name:      '%s'", vtun.name);
+  GST_LOG_OBJECT (e, "   type:      %016x", (guint) vtun.type);
+  GST_LOG_OBJECT (e, "   caps:      %016x", (guint) vtun.capability);
+  GST_LOG_OBJECT (e, "   rlow:      %016x", (guint) vtun.rangelow);
+  GST_LOG_OBJECT (e, "   rhigh:     %016x", (guint) vtun.rangehigh);
+  GST_LOG_OBJECT (e, "   audmode:   %016x", (guint) vtun.audmode);
+
+  v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
+  channel = GST_TUNER_CHANNEL (v4l2channel);
+  channel->label = g_strdup ((const gchar *) vtun.name);
+  channel->flags = GST_TUNER_CHANNEL_FREQUENCY | GST_TUNER_CHANNEL_AUDIO;
+  v4l2channel->index = 0;
+  v4l2channel->tuner = 0;
+
+  channel->freq_multiplicator =
+      62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
+  channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
+  channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
+  channel->min_signal = 0;
+  channel->max_signal = 0xffff;
+
+  v4l2object->channels =
+      g_list_prepend (v4l2object->channels, (gpointer) channel);
+
+  v4l2object->channels = g_list_reverse (v4l2object->channels);
+
+  GST_DEBUG_OBJECT (e, "done");
+  return TRUE;
+
+  /* ERRORS */
+tuner_failed:
+  {
+    GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+        (_("Failed to get settings of tuner %d on device '%s'."),
+            vtun.index, v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+caps_failed:
+  {
+    GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+        (_("Error getting capabilities for device '%s'."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+not_a_tuner:
+  {
+    GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+        (_("Device '%s' is not a tuner."),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2radio_get_input (GstV4l2Object * v4l2object, gint * input)
+{
+  GST_DEBUG_OBJECT (v4l2object->element, "trying to get radio input");
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (!v4l2object->channels)
+    goto input_failed;
+
+  *input = 0;
+
+  GST_DEBUG_OBJECT (v4l2object->element, "input: %d", 0);
+
+  return TRUE;
+
+  /* ERRORS */
+input_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to get radio input on device '%s'. "),
+            v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2radio_set_input (GstV4l2Object * v4l2object, gint input)
+{
+  GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  if (!v4l2object->channels)
+    goto input_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+input_failed:
+  {
+    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+        (_("Failed to set input %d on device %s."),
+            input, v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_v4l2radio_set_mute_on (GstV4l2Radio * radio, gboolean on)
+{
+  gint res;
+  struct v4l2_control vctrl;
+
+  GST_DEBUG_OBJECT (radio, "setting current tuner mute state: %d", on);
+
+  if (!GST_V4L2_IS_OPEN (radio->v4l2object))
+    return FALSE;
+
+  memset (&vctrl, 0, sizeof (vctrl));
+  vctrl.id = V4L2_CID_AUDIO_MUTE;
+  vctrl.value = on;
+
+  GST_DEBUG_OBJECT (radio, "radio fd: %d", radio->v4l2object->video_fd);
+
+  res = ioctl (radio->v4l2object->video_fd, VIDIOC_S_CTRL, &vctrl);
+  GST_DEBUG_OBJECT (radio, "mute state change result: %d", res);
+  if (res < 0)
+    goto freq_failed;
+
+  return TRUE;
+
+  /* ERRORS */
+freq_failed:
+  {
+    GST_ELEMENT_WARNING (radio, RESOURCE, SETTINGS,
+        (_("Failed to change mute state for device '%s'."),
+            radio->v4l2object->videodev), GST_ERROR_SYSTEM);
+    return FALSE;
+  }
+}
+
+gboolean
+gst_v4l2radio_set_mute (GstV4l2Radio * radio)
+{
+  return gst_v4l2radio_set_mute_on (radio, TRUE);
+}
+
+gboolean
+gst_v4l2radio_set_unmute (GstV4l2Radio * radio)
+{
+  return gst_v4l2radio_set_mute_on (radio, FALSE);
+}
diff -urpNB gst-plugins-good.orig/sys/v4l2/v4l2radio_calls.h gst-plugins-good/sys/v4l2/v4l2radio_calls.h
--- gst-plugins-good.orig/sys/v4l2/v4l2radio_calls.h	1970-01-01 03:00:00.000000000 +0300
+++ gst-plugins-good/sys/v4l2/v4l2radio_calls.h	2011-01-20 23:22:15.000000000 +0300
@@ -0,0 +1,38 @@
+/* GStreamer
+ * 
+ * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com>
+ * 
+ * v4l2radio_calls.h - additional system calls for radio support
+ *
+ * This 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.
+ *
+ * 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+#include "gstv4l2radio.h"
+
+#ifndef __V4L2RADIO_CALLS_H__
+#define __V4L2RADIO_CALLS_H__
+
+gboolean   gst_v4l2radio_fill_channel_list(GstV4l2Radio * radio);
+
+gboolean   gst_v4l2radio_get_input (GstV4l2Object * v4l2object, gint * input);
+
+gboolean   gst_v4l2radio_set_input (GstV4l2Object * v4l2object, gint input);
+
+gboolean   gst_v4l2radio_set_mute(GstV4l2Radio *radio);
+
+gboolean   gst_v4l2radio_set_unmute(GstV4l2Radio *radio);
+
+#endif /*__V4L2RADIO_CALLS_H__*/
