mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 17:18:15 +00:00
v4l2: new v4l2radio element to control analog radio devices
https://bugzilla.gnome.org/show_bug.cgi?id=640118
This commit is contained in:
parent
0a39cec7e3
commit
e7a63c34ac
8 changed files with 730 additions and 1 deletions
|
@ -229,6 +229,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
|
||||
|
||||
|
|
|
@ -154,6 +154,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" />
|
||||
|
|
|
@ -2048,6 +2048,20 @@ GST_IS_V4L2SINK_CLASS
|
|||
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>
|
||||
|
|
|
@ -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 <4ernov@gmail.com></author>
|
||||
</element>
|
||||
</elements>
|
||||
</plugin>
|
||||
</plugin>
|
||||
|
|
|
@ -13,6 +13,7 @@ libgstvideo4linux2_la_SOURCES = gstv4l2.c \
|
|||
gstv4l2object.c \
|
||||
gstv4l2bufferpool.c \
|
||||
gstv4l2src.c \
|
||||
gstv4l2radio.c \
|
||||
gstv4l2tuner.c \
|
||||
gstv4l2vidorient.c \
|
||||
v4l2_calls.c \
|
||||
|
@ -51,6 +52,7 @@ noinst_HEADERS = \
|
|||
gstv4l2object.h \
|
||||
gstv4l2sink.h \
|
||||
gstv4l2src.h \
|
||||
gstv4l2radio.h \
|
||||
gstv4l2tuner.h \
|
||||
gstv4l2vidorient.h \
|
||||
gstv4l2xoverlay.h \
|
||||
|
|
|
@ -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", */
|
||||
|
|
633
sys/v4l2/gstv4l2radio.c
Normal file
633
sys/v4l2/gstv4l2radio.c
Normal file
|
@ -0,0 +1,633 @@
|
|||
/* GStreamer v4l2 radio tuner element
|
||||
* 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 "gst/gst-i18n-plugin.h"
|
||||
|
||||
#include "gstv4l2tuner.h"
|
||||
#include "gstv4l2radio.h"
|
||||
#include "v4l2_calls.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (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
|
||||
};
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2radio_set_mute (GstV4l2Radio * radio)
|
||||
{
|
||||
return gst_v4l2radio_set_mute_on (radio, TRUE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2radio_set_unmute (GstV4l2Radio * radio)
|
||||
{
|
||||
return gst_v4l2radio_set_mute_on (radio, FALSE);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
68
sys/v4l2/gstv4l2radio.h
Normal file
68
sys/v4l2/gstv4l2radio.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* GStreamer v4l2 radio tuner element
|
||||
* 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"
|
||||
|
||||
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: private #GstV4l2Object
|
||||
*
|
||||
* Opaque video4linux2 radio tuner element
|
||||
*/
|
||||
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__ */
|
Loading…
Reference in a new issue