Some interface implementations for video4linux/video4linux2 plugins: a Tuner interfac...
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / gstv4l2tuner.c
1 /* GStreamer Tuner interface implementation
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * gstv4l2tuner.c: tuner interface implementation for V4L2
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <gst/gst.h>
27 #include <gst/tuner/tuner.h>
28
29 #include "gstv4l2tuner.h"
30 #include "gstv4l2element.h"
31 #include "v4l2_calls.h"
32
33 static void     gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *klass);
34 static void     gst_v4l2_tuner_channel_init     (GstV4l2TunerChannel *channel);
35
36 static void     gst_v4l2_tuner_norm_class_init  (GstV4l2TunerNormClass *klass);
37 static void     gst_v4l2_tuner_norm_init        (GstV4l2TunerNorm *norm);
38
39 static const GList *
40                 gst_v4l2_tuner_list_channels    (GstTuner        *mixer);
41 static void     gst_v4l2_tuner_set_channel      (GstTuner        *mixer,
42                                                  GstTunerChannel *channel);
43 static const GstTunerChannel *
44                 gst_v4l2_tuner_get_channel      (GstTuner        *mixer);
45
46 static const GList *
47                 gst_v4l2_tuner_list_norms       (GstTuner        *mixer);
48 static void     gst_v4l2_tuner_set_norm         (GstTuner        *mixer,
49                                                  GstTunerNorm    *norm);
50 static const GstTunerNorm *
51                 gst_v4l2_tuner_get_norm         (GstTuner        *mixer);
52
53 static void     gst_v4l2_tuner_set_frequency    (GstTuner        *mixer,
54                                                  GstTunerChannel *channel,
55                                                  gulong           frequency);
56 static gulong   gst_v4l2_tuner_get_frequency    (GstTuner        *mixer,
57                                                  GstTunerChannel *channel);
58 static gint     gst_v4l2_tuner_signal_strength  (GstTuner        *mixer,
59                                                  GstTunerChannel *channel);
60
61 static GstTunerNormClass *norm_parent_class = NULL;
62 static GstTunerChannelClass *channel_parent_class = NULL;
63
64 GType
65 gst_v4l2_tuner_channel_get_type (void)
66 {
67   static GType gst_v4l2_tuner_channel_type = 0;
68
69   if (!gst_v4l2_tuner_channel_type) {
70     static const GTypeInfo v4l2_tuner_channel_info = {
71       sizeof (GstV4l2TunerChannelClass),
72       NULL,
73       NULL,
74       (GClassInitFunc) gst_v4l2_tuner_channel_class_init,
75       NULL,
76       NULL,
77       sizeof (GstV4l2TunerChannel),
78       0,
79       (GInstanceInitFunc) gst_v4l2_tuner_channel_init,
80       NULL
81     };
82
83     gst_v4l2_tuner_channel_type =
84         g_type_register_static (GST_TYPE_TUNER_CHANNEL,
85                                 "GstV4l2TunerChannel",
86                                 &v4l2_tuner_channel_info, 0);
87   }
88
89   return gst_v4l2_tuner_channel_type;
90 }
91
92 static void
93 gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *klass)
94 {
95   channel_parent_class = g_type_class_ref (GST_TYPE_TUNER_CHANNEL);
96 }
97
98 static void
99 gst_v4l2_tuner_channel_init (GstV4l2TunerChannel *channel)
100 {
101   channel->index = 0;
102   channel->tuner = 0;
103   channel->audio = 0;
104 }
105
106 GType
107 gst_v4l2_tuner_norm_get_type (void)
108 {
109   static GType gst_v4l2_tuner_norm_type = 0;
110
111   if (!gst_v4l2_tuner_norm_type) {
112     static const GTypeInfo v4l2_tuner_norm_info = {
113       sizeof (GstV4l2TunerNormClass),
114       NULL,
115       NULL,
116       (GClassInitFunc) gst_v4l2_tuner_norm_class_init,
117       NULL,
118       NULL,
119       sizeof (GstV4l2TunerNorm),
120       0,
121       (GInstanceInitFunc) gst_v4l2_tuner_norm_init,
122       NULL
123     };
124
125     gst_v4l2_tuner_norm_type =
126         g_type_register_static (GST_TYPE_TUNER_NORM,
127                                 "GstV4l2TunerNorm",
128                                 &v4l2_tuner_norm_info, 0);
129   }
130
131   return gst_v4l2_tuner_norm_type;
132 }
133
134 static void
135 gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass *klass)
136 {
137   norm_parent_class = g_type_class_ref (GST_TYPE_TUNER_NORM);
138 }
139
140 static void
141 gst_v4l2_tuner_norm_init (GstV4l2TunerNorm *norm)
142 {
143   norm->index = 0;
144 }
145
146 void
147 gst_v4l2_tuner_interface_init (GstTunerClass *klass)
148 {
149   /* default virtual functions */
150   klass->list_channels = gst_v4l2_tuner_list_channels;
151   klass->set_channel = gst_v4l2_tuner_set_channel;
152   klass->get_channel = gst_v4l2_tuner_get_channel;
153
154   klass->list_norms = gst_v4l2_tuner_list_norms;
155   klass->set_norm = gst_v4l2_tuner_set_norm;
156   klass->get_norm = gst_v4l2_tuner_get_norm;
157
158   klass->set_frequency = gst_v4l2_tuner_set_frequency;
159   klass->get_frequency = gst_v4l2_tuner_get_frequency;
160   klass->signal_strength = gst_v4l2_tuner_signal_strength;
161 }
162
163 static gboolean
164 gst_v4l2_tuner_is_sink (GstV4l2Element *v4l2element)
165 {
166   const GList *pads = gst_element_get_pad_list (GST_ELEMENT (v4l2element));
167   GstPadDirection dir = GST_PAD_UNKNOWN;
168
169   /* get direction */
170   if (pads && g_list_length ((GList *) pads) == 1)
171     dir = GST_PAD_DIRECTION (GST_PAD (pads->data));
172
173   return (dir == GST_PAD_SINK);
174 }
175
176 static gboolean
177 gst_v4l2_tuner_contains_channel (GstV4l2Element      *v4l2element,
178                                  GstV4l2TunerChannel *v4l2channel)
179 {
180   const GList *item;
181
182   for (item = v4l2element->channels; item != NULL; item = item->next)
183     if (item->data == v4l2channel)
184       return TRUE;
185
186   return FALSE;
187 }
188
189 static const GList *
190 gst_v4l2_tuner_list_channels (GstTuner *mixer)
191 {
192   /* ... or output, if we're a sink... */
193   return GST_V4L2ELEMENT (mixer)->channels;
194 }
195
196 static void
197 gst_v4l2_tuner_set_channel (GstTuner        *mixer,
198                             GstTunerChannel *channel)
199 {
200   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
201   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
202
203   /* assert that we're opened and that we're using a known item */
204   g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element));
205   g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel));
206
207   /* ... or output, if we're a sink... */
208   if (gst_v4l2_tuner_is_sink (v4l2element))
209     gst_v4l2_set_output (v4l2element, v4l2channel->index);
210   else
211     gst_v4l2_set_input (v4l2element, v4l2channel->index);
212 }
213
214 static const GstTunerChannel *
215 gst_v4l2_tuner_get_channel (GstTuner *mixer)
216 {
217   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
218   GList *item;
219   gint channel;
220
221   /* assert that we're opened and that we're using a known item */
222   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), NULL);
223
224   /* ... or output, if we're a sink... */
225   if (gst_v4l2_tuner_is_sink (v4l2element))
226     gst_v4l2_get_output (v4l2element, &channel);
227   else
228     gst_v4l2_get_input (v4l2element, &channel);
229
230   for (item = v4l2element->channels; item != NULL; item = item->next) {
231     if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index)
232       return (const GstTunerChannel *) item->data;
233   }
234
235   return NULL;
236 }
237
238 static gboolean
239 gst_v4l2_tuner_contains_norm (GstV4l2Element   *v4l2element,
240                               GstV4l2TunerNorm *v4l2norm)
241 {
242   const GList *item;
243
244   for (item = v4l2element->norms; item != NULL; item = item->next)
245     if (item->data == v4l2norm)
246       return TRUE;
247
248   return FALSE;
249 }
250
251 static const GList *
252 gst_v4l2_tuner_list_norms (GstTuner *mixer)
253 {
254   return GST_V4L2ELEMENT (mixer)->norms;
255 }
256
257 static void
258 gst_v4l2_tuner_set_norm (GstTuner     *mixer,
259                          GstTunerNorm *norm)
260 {
261   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
262   GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm);
263
264   /* assert that we're opened and that we're using a known item */
265   g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element));
266   g_return_if_fail (gst_v4l2_tuner_contains_norm (v4l2element, v4l2norm));
267
268   gst_v4l2_set_norm (v4l2element, v4l2norm->index);
269 }
270
271 static const GstTunerNorm *
272 gst_v4l2_tuner_get_norm (GstTuner *mixer)
273 {
274   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
275   GList *item;
276   v4l2_std_id norm;
277
278   /* assert that we're opened and that we're using a known item */
279   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), NULL);
280
281   gst_v4l2_get_norm (v4l2element, &norm);
282
283   for (item = v4l2element->norms; item != NULL; item = item->next) {
284     if (norm == GST_V4L2_TUNER_NORM (item->data)->index)
285       return (const GstTunerNorm *) item->data;
286   }
287
288   return NULL;
289 }
290
291 static void
292 gst_v4l2_tuner_set_frequency (GstTuner        *mixer,
293                               GstTunerChannel *channel,
294                               gulong           frequency)
295 {
296   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
297   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
298   gint chan;
299
300   /* assert that we're opened and that we're using a known item */
301   g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element));
302   g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
303                         GST_TUNER_CHANNEL_FREQUENCY));
304   g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel));
305
306   gst_v4l2_get_input (v4l2element, &chan);
307   if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
308       GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
309     gst_v4l2_set_frequency (v4l2element, v4l2channel->tuner, frequency);
310   }
311 }
312
313 static gulong
314 gst_v4l2_tuner_get_frequency (GstTuner        *mixer,
315                               GstTunerChannel *channel)
316 {
317   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
318   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
319   gint chan;
320   gulong frequency = 0;
321
322   /* assert that we're opened and that we're using a known item */
323   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), 0);
324   g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
325                                 GST_TUNER_CHANNEL_FREQUENCY), 0);
326   g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element,
327                                                          v4l2channel), 0);
328
329   gst_v4l2_get_input (v4l2element, &chan);
330   if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
331       GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
332     gst_v4l2_get_frequency (v4l2element, v4l2channel->tuner, &frequency);
333   }
334
335   return frequency;
336 }
337
338 static gint
339 gst_v4l2_tuner_signal_strength (GstTuner        *mixer,
340                                 GstTunerChannel *channel)
341 {
342   GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
343   GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
344   gint chan;
345   gulong signal = 0;
346
347   /* assert that we're opened and that we're using a known item */
348   g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), 0);
349   g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
350                                 GST_TUNER_CHANNEL_FREQUENCY), 0);
351   g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element,
352                                                          v4l2channel), 0);
353
354   gst_v4l2_get_input (v4l2element, &chan);
355   if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
356       GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
357     gst_v4l2_signal_strength (v4l2element, v4l2channel->tuner, &signal);
358   }
359
360   return signal;
361 }