1 /*
2 * parsechannels.c -
3 * Copyright (C) 2008 Zaheer Abbas Merali
4 *
5 * Authors:
6 * Zaheer Abbas Merali <zaheerabbas at merali dot org>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <gst/gst.h>
33
34 #include <gst/gst-i18n-plugin.h>
35
36 #include "parsechannels.h"
37
38 #include <linux/dvb/frontend.h>
39
40 GST_DEBUG_CATEGORY_EXTERN (dvb_base_bin_debug);
41 #define GST_CAT_DEFAULT dvb_base_bin_debug
42
43 typedef enum
44 {
45 CHANNEL_CONF_FORMAT_NONE,
46 CHANNEL_CONF_FORMAT_DVBV5,
47 CHANNEL_CONF_FORMAT_ZAP
48 } GstDvbChannelConfFormat;
49
50 typedef gboolean (*GstDvbV5ChannelsConfPropSetFunction) (GstElement *
51 dvbbasebin, const gchar * property, GKeyFile * kf,
52 const gchar * channel_name, const gchar * key);
53
54 typedef struct
55 {
56 const gchar *conf_property;
57 const gchar *elem_property;
58 GstDvbV5ChannelsConfPropSetFunction set_func;
59 } GstDvbV5ChannelsConfToPropertyMap;
60
61 static gboolean parse_and_configure_from_v5_conf_file (GstElement * dvbbasebin,
62 const gchar * filename, const gchar * channel_name, GError ** error);
63 static gboolean parse_and_configure_from_zap_conf_file (GstElement * dvbbasebin,
64 const gchar * filename, const gchar * channel_name, GError ** error);
65 static GstDvbChannelConfFormat detect_file_format (const gchar * filename);
66
67 static gboolean gst_dvb_base_bin_conf_set_string (GstElement * dvbbasebin,
68 const gchar * property, GKeyFile * kf, const gchar * channel_name,
69 const gchar * key);
70 static gboolean gst_dvb_base_bin_conf_set_uint (GstElement * dvbbasebin,
71 const gchar * property, GKeyFile * kf, const gchar * channel_name,
72 const gchar * key);
73 static gboolean gst_dvb_base_bin_conf_set_int (GstElement * dvbbasebin,
74 const gchar * property, GKeyFile * kf, const gchar * channel_name,
75 const gchar * key);
76 static gboolean gst_dvb_base_bin_conf_set_inversion (GstElement * dvbbasebin,
77 const gchar * property, GKeyFile * kf, const gchar * channel_name,
78 const gchar * key);
79 static gboolean gst_dvb_base_bin_conf_set_guard (GstElement * dvbbasebin,
80 const gchar * property, GKeyFile * kf, const gchar * channel_name,
81 const gchar * key);
82 static gboolean gst_dvb_base_bin_conf_set_trans_mode (GstElement * dvbbasebin,
83 const gchar * property, GKeyFile * kf, const gchar * channel_name,
84 const gchar * key);
85 static gboolean gst_dvb_base_bin_conf_set_code_rate (GstElement * dvbbasebin,
86 const gchar * property, GKeyFile * kf, const gchar * channel_name,
87 const gchar * key);
88 static gboolean gst_dvb_base_bin_conf_set_delsys (GstElement * dvbbasebin,
89 const gchar * property, GKeyFile * kf, const gchar * channel_name,
90 const gchar * key);
91 static gboolean gst_dvb_base_bin_conf_set_hierarchy (GstElement * dvbbasebin,
92 const gchar * property, GKeyFile * kf, const gchar * channel_name,
93 const gchar * key);
94 static gboolean gst_dvb_base_bin_conf_set_modulation (GstElement * dvbbasebin,
95 const gchar * property, GKeyFile * kf, const gchar * channel_name,
96 const gchar * key);
97 static GHashTable *parse_channels_conf_from_zap_file (GstElement * dvbbasebin,
98 const gchar * filename, GError ** error);
99 static gboolean remove_channel_from_hash (gpointer key, gpointer value,
100 gpointer user_data);
101 static void destroy_channels_hash (GHashTable * channels);
102
103 GstDvbV5ChannelsConfToPropertyMap dvbv5_prop_map[] = {
104 {"SERVICE_ID", "program-numbers", gst_dvb_base_bin_conf_set_string},
105 {"FREQUENCY", "frequency", gst_dvb_base_bin_conf_set_uint},
106 {"BANDWIDTH_HZ", "bandwidth-hz", gst_dvb_base_bin_conf_set_uint},
107 {"INVERSION", "inversion", gst_dvb_base_bin_conf_set_inversion},
108 {"GUARD_INTERVAL", "guard", gst_dvb_base_bin_conf_set_guard},
109 {"TRANSMISSION_MODE", "trans-mode", gst_dvb_base_bin_conf_set_trans_mode},
110 {"HIERARCHY", "hierarchy", gst_dvb_base_bin_conf_set_hierarchy},
111 {"MODULATION", "modulation", gst_dvb_base_bin_conf_set_modulation},
112 {"CODE_RATE_HP", "code-rate-hp", gst_dvb_base_bin_conf_set_code_rate},
113 {"CODE_RATE_LP", "code-rate-lp", gst_dvb_base_bin_conf_set_code_rate},
114 {"ISDBT_LAYER_ENABLED", "isdbt-layer-enabled",
115 gst_dvb_base_bin_conf_set_uint},
116 {"ISDBT_PARTIAL_RECEPTION", "isdbt-partial-reception",
117 gst_dvb_base_bin_conf_set_int},
118 {"ISDBT_SOUND_BROADCASTING", "isdbt-sound-broadcasting",
119 gst_dvb_base_bin_conf_set_int},
120 {"ISDBT_SB_SUBCHANNEL_ID", "isdbt-sb-subchannel-id",
121 gst_dvb_base_bin_conf_set_int},
122 {"ISDBT_SB_SEGMENT_IDX", "isdbt-sb-segment-idx",
123 gst_dvb_base_bin_conf_set_int},
124 {"ISDBT_SB_SEGMENT_COUNT", "isdbt-sb-segment-count", gst_dvb_base_bin_conf_set_int}, /* Range in files start from 0, property starts from 1 */
125 {"ISDBT_LAYERA_FEC", "isdbt-layera-fec", gst_dvb_base_bin_conf_set_code_rate},
126 {"ISDBT_LAYERA_MODULATION", "isdbt-layera-modulation",
127 gst_dvb_base_bin_conf_set_modulation},
128 {"ISDBT_LAYERA_SEGMENT_COUNT", "isdbt-layera-segment-count",
129 gst_dvb_base_bin_conf_set_int},
130 {"ISDBT_LAYERA_TIME_INTERLEAVING", "isdbt-layera-time-interleaving",
131 gst_dvb_base_bin_conf_set_int},
132 {"ISDBT_LAYERB_FEC", "isdbt-layerb-fec", gst_dvb_base_bin_conf_set_code_rate},
133 {"ISDBT_LAYERB_MODULATION", "isdbt-layerb-modulation",
134 gst_dvb_base_bin_conf_set_modulation},
135 {"ISDBT_LAYERB_SEGMENT_COUNT", "isdbt-layerb-segment-count",
136 gst_dvb_base_bin_conf_set_int},
137 {"ISDBT_LAYERB_TIME_INTERLEAVING", "isdbt-layerb-time-interleaving",
138 gst_dvb_base_bin_conf_set_int},
139 {"ISDBT_LAYERC_FEC", "isdbt-layerc-fec", gst_dvb_base_bin_conf_set_code_rate},
140 {"ISDBT_LAYERC_MODULATION", "isdbt-layerc-modulation",
141 gst_dvb_base_bin_conf_set_modulation},
142 {"ISDBT_LAYERC_SEGMENT_COUNT", "isdbt-layerc-segment-count",
143 gst_dvb_base_bin_conf_set_int},
144 {"ISDBT_LAYERC_TIME_INTERLEAVING", "isdbt-layerc-time-interleaving",
145 gst_dvb_base_bin_conf_set_int},
146 {"DELIVERY_SYSTEM", "delsys", gst_dvb_base_bin_conf_set_delsys},
147 {NULL,}
148 };
149
150 /* TODO:
151 * Store the channels hash table around instead of constantly parsing it
152 * Detect when the file changed on disk
153 */
154
155 static gint
gst_dvb_base_bin_find_string_in_array(const gchar ** array,const gchar * str)156 gst_dvb_base_bin_find_string_in_array (const gchar ** array, const gchar * str)
157 {
158 gint i = 0;
159 const gchar *cur;
160 while ((cur = array[i])) {
161 if (strcmp (cur, str) == 0)
162 return i;
163
164 i++;
165 }
166
167 return -1;
168 }
169
170 static gboolean
gst_dvb_base_bin_conf_set_property_from_string_array(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key,const gchar ** strings,gint default_value)171 gst_dvb_base_bin_conf_set_property_from_string_array (GstElement * dvbbasebin,
172 const gchar * property, GKeyFile * kf, const gchar * channel_name,
173 const gchar * key, const gchar ** strings, gint default_value)
174 {
175 gchar *str;
176 gint v;
177
178 str = g_key_file_get_string (kf, channel_name, key, NULL);
179 v = gst_dvb_base_bin_find_string_in_array (strings, str);
180 if (v == -1) {
181 GST_WARNING_OBJECT (dvbbasebin, "Unexpected value '%s' for property "
182 "'%s', using default: '%d'", str, property, default_value);
183 v = default_value;
184 }
185
186 g_free (str);
187 g_object_set (dvbbasebin, property, v, NULL);
188 return TRUE;
189 }
190
191 static gboolean
gst_dvb_base_bin_conf_set_string(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)192 gst_dvb_base_bin_conf_set_string (GstElement * dvbbasebin,
193 const gchar * property, GKeyFile * kf, const gchar * channel_name,
194 const gchar * key)
195 {
196 gchar *str;
197
198 str = g_key_file_get_string (kf, channel_name, key, NULL);
199 if (!str) {
200 GST_WARNING_OBJECT (dvbbasebin,
201 "Could not get value for '%s' on channel '%s'", key, channel_name);
202 return FALSE;
203 }
204
205 g_object_set (dvbbasebin, property, str, NULL);
206 g_free (str);
207 return TRUE;
208 }
209
210 static gboolean
gst_dvb_base_bin_conf_set_uint(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)211 gst_dvb_base_bin_conf_set_uint (GstElement * dvbbasebin, const gchar * property,
212 GKeyFile * kf, const gchar * channel_name, const gchar * key)
213 {
214 guint64 v;
215
216 v = g_key_file_get_uint64 (kf, channel_name, key, NULL);
217 if (!v) {
218 GST_WARNING_OBJECT (dvbbasebin,
219 "Could not get value for '%s' on channel '%s'", key, channel_name);
220 return FALSE;
221 }
222
223 g_object_set (dvbbasebin, property, (guint) v, NULL);
224 return TRUE;
225 }
226
227 static gboolean
gst_dvb_base_bin_conf_set_int(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)228 gst_dvb_base_bin_conf_set_int (GstElement * dvbbasebin, const gchar * property,
229 GKeyFile * kf, const gchar * channel_name, const gchar * key)
230 {
231 gint v;
232
233 v = g_key_file_get_integer (kf, channel_name, key, NULL);
234 if (!v) {
235 GST_WARNING_OBJECT (dvbbasebin,
236 "Could not get value for '%s' on channel '%s'", key, channel_name);
237 return FALSE;
238 }
239
240 g_object_set (dvbbasebin, property, v, NULL);
241 return TRUE;
242 }
243
244 static gboolean
gst_dvb_base_bin_conf_set_inversion(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)245 gst_dvb_base_bin_conf_set_inversion (GstElement * dvbbasebin,
246 const gchar * property, GKeyFile * kf, const gchar * channel_name,
247 const gchar * key)
248 {
249 gchar *str;
250 gint v;
251
252 str = g_key_file_get_string (kf, channel_name, key, NULL);
253 if (!str) {
254 GST_WARNING_OBJECT (dvbbasebin,
255 "Could not get value for '%s' on channel '%s'", key, channel_name);
256 return FALSE;
257 }
258
259 if (strcmp (str, "AUTO") == 0)
260 v = 2;
261 else if (strcmp (str, "ON") == 0)
262 v = 1;
263 else
264 v = 0; /* OFF */
265
266 g_free (str);
267 g_object_set (dvbbasebin, property, v, NULL);
268 return TRUE;
269 }
270
271 static gboolean
gst_dvb_base_bin_conf_set_guard(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)272 gst_dvb_base_bin_conf_set_guard (GstElement * dvbbasebin,
273 const gchar * property, GKeyFile * kf, const gchar * channel_name,
274 const gchar * key)
275 {
276 const gchar *guards[] = {
277 "1/32", "1/16", "1/8", "1/4", "auto",
278 "1/128", "19/128", "19/256",
279 "PN420", "PN595", "PN945", NULL
280 };
281 return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin,
282 property, kf, channel_name, key, guards, 4);
283 }
284
285 static gboolean
gst_dvb_base_bin_conf_set_trans_mode(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)286 gst_dvb_base_bin_conf_set_trans_mode (GstElement * dvbbasebin,
287 const gchar * property, GKeyFile * kf, const gchar * channel_name,
288 const gchar * key)
289 {
290 const gchar *trans_modes[] = {
291 "2K", "8K", "AUTO", "4K", "1K",
292 "16K", "32K", "C1", "C3780", NULL
293 };
294 return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin,
295 property, kf, channel_name, key, trans_modes, 2);
296 }
297
298 static gboolean
gst_dvb_base_bin_conf_set_code_rate(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)299 gst_dvb_base_bin_conf_set_code_rate (GstElement * dvbbasebin,
300 const gchar * property, GKeyFile * kf, const gchar * channel_name,
301 const gchar * key)
302 {
303 const gchar *code_rates[] = {
304 "NONE", "1/2", "2/3", "3/4", "4/5",
305 "5/6", "6/7", "7/8", "8/9", "AUTO",
306 "3/5", "9/10", "2/5", NULL
307 };
308 return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin,
309 property, kf, channel_name, key, code_rates, 9);
310 }
311
312 static gboolean
gst_dvb_base_bin_conf_set_delsys(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)313 gst_dvb_base_bin_conf_set_delsys (GstElement * dvbbasebin,
314 const gchar * property, GKeyFile * kf, const gchar * channel_name,
315 const gchar * key)
316 {
317 const gchar *delsys[] = {
318 "UNDEFINED", "DVBCA", "DVBCB", "DVBT", "DSS",
319 "DVBS", "DVBS2", "DVBH", "ISDBT", "ISDBS",
320 "ISDBC", "ATSC", "ATSCMH", "DTMB", "CMMB",
321 "DAB", "DVBT2", "TURBO", "DVBCC", NULL
322 };
323 return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin,
324 property, kf, channel_name, key, delsys, 0);
325 }
326
327 static gboolean
gst_dvb_base_bin_conf_set_hierarchy(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)328 gst_dvb_base_bin_conf_set_hierarchy (GstElement * dvbbasebin,
329 const gchar * property, GKeyFile * kf, const gchar * channel_name,
330 const gchar * key)
331 {
332 const gchar *hierarchies[] = {
333 "NONE", "1", "2", "4", "AUTO", NULL
334 };
335 return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin,
336 property, kf, channel_name, key, hierarchies, 4);
337 }
338
339 static gboolean
gst_dvb_base_bin_conf_set_modulation(GstElement * dvbbasebin,const gchar * property,GKeyFile * kf,const gchar * channel_name,const gchar * key)340 gst_dvb_base_bin_conf_set_modulation (GstElement * dvbbasebin,
341 const gchar * property, GKeyFile * kf, const gchar * channel_name,
342 const gchar * key)
343 {
344 const gchar *modulations[] = {
345 "QPSK", "QAM/16", "QAM/32", "QAM/64",
346 "QAM/128", "QAM/256", "QAM/AUTO", "VSB/8",
347 "VSB/16", "PSK/8", "APSK/16", "APSK/32",
348 "DQPSK", "QAM/4_NR", NULL
349 };
350 return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin,
351 property, kf, channel_name, key, modulations, 6);
352 }
353
354 /* FIXME: is channel_name guaranteed to be ASCII or UTF-8? */
355 static gboolean
parse_and_configure_from_v5_conf_file(GstElement * dvbbasebin,const gchar * filename,const gchar * channel_name,GError ** error)356 parse_and_configure_from_v5_conf_file (GstElement * dvbbasebin,
357 const gchar * filename, const gchar * channel_name, GError ** error)
358 {
359 GKeyFile *keyfile;
360 gchar **keys, **keys_p;
361 GError *err = NULL;
362
363 keyfile = g_key_file_new ();
364 if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &err))
365 goto load_error;
366
367 if (!g_key_file_has_group (keyfile, channel_name))
368 goto unknown_channel;
369
370 keys = g_key_file_get_keys (keyfile, channel_name, NULL, &err);
371 if (!keys)
372 goto no_properties;
373
374 keys_p = keys;
375 while (*keys_p) {
376 const gchar *k = *keys_p;
377 const GstDvbV5ChannelsConfToPropertyMap *map_entry = dvbv5_prop_map;
378 gboolean property_found = FALSE;
379
380 GST_LOG_OBJECT (dvbbasebin, "Setting property %s", k);
381
382 while (map_entry->conf_property) {
383 if (strcmp (map_entry->conf_property, k) == 0) {
384 if (!map_entry->set_func (dvbbasebin, map_entry->elem_property, keyfile,
385 channel_name, k))
386 goto property_error;
387 property_found = TRUE;
388 break;
389 }
390 map_entry++;
391 }
392
393 if (!property_found)
394 GST_WARNING_OBJECT (dvbbasebin, "Failed to map property '%s'", k);
395
396 keys_p++;
397 }
398
399 GST_DEBUG_OBJECT (dvbbasebin, "Successfully parsed channel configuration "
400 "file '%s'", filename);
401 g_strfreev (keys);
402 g_key_file_unref (keyfile);
403 return TRUE;
404
405 load_error:
406 if ((err->domain == G_FILE_ERROR && err->code == G_FILE_ERROR_NOENT) ||
407 (err->domain == G_KEY_FILE_ERROR
408 && err->code == G_KEY_FILE_ERROR_NOT_FOUND)) {
409 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND,
410 _("Couldn't find channel configuration file"));
411 } else {
412 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
413 _("Couldn't load channel configuration file: '%s'"), err->message);
414 }
415 g_clear_error (&err);
416 return FALSE;
417
418 unknown_channel:
419 {
420 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND,
421 _("Couldn't find details for channel '%s'"), channel_name);
422 g_key_file_unref (keyfile);
423 g_clear_error (&err);
424 return FALSE;
425 }
426
427 no_properties:
428 {
429 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND,
430 _("No properties for channel '%s'"), channel_name);
431 g_key_file_unref (keyfile);
432 g_clear_error (&err);
433 return FALSE;
434 }
435
436 property_error:
437 {
438 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
439 _("Failed to set properties for channel '%s'"), channel_name);
440 g_key_file_unref (keyfile);
441 g_clear_error (&err);
442 return FALSE;
443 }
444 }
445
446 static GHashTable *
parse_channels_conf_from_zap_file(GstElement * dvbbasebin,const gchar * filename,GError ** error)447 parse_channels_conf_from_zap_file (GstElement * dvbbasebin,
448 const gchar * filename, GError ** error)
449 {
450 gchar *contents;
451 gchar **lines;
452 gchar *line;
453 gchar **fields;
454 int i, parsedchannels = 0;
455 GHashTable *res;
456 GError *err = NULL;
457 const gchar *terrestrial[] = { "inversion", "bandwidth",
458 "code-rate-hp", "code-rate-lp", "modulation", "transmission-mode",
459 "guard", "hierarchy"
460 };
461 const gchar *satellite[] = { "polarity", "diseqc-source",
462 "symbol-rate"
463 };
464 const gchar *cable[] = { "inversion", "symbol-rate", "code-rate-hp",
465 "modulation"
466 };
467
468 GST_INFO_OBJECT (dvbbasebin, "parsing '%s'", filename);
469
470 if (!g_file_get_contents (filename, &contents, NULL, &err))
471 goto open_fail;
472
473 lines = g_strsplit (contents, "\n", 0);
474 res = g_hash_table_new (g_str_hash, g_str_equal);
475
476 i = 0;
477 line = lines[0];
478 while (line != NULL) {
479 GHashTable *params;
480 int j, numfields;
481
482 if (line[0] == '#')
483 goto next_line;
484
485 params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
486 fields = g_strsplit (line, ":", 0);
487 numfields = g_strv_length (fields);
488
489 switch (numfields) {
490 case 13: /* terrestrial */
491 g_hash_table_insert (params, g_strdup ("type"),
492 g_strdup ("terrestrial"));
493 for (j = 2; j <= 9; j++) {
494 g_hash_table_insert (params, g_strdup (terrestrial[j - 2]),
495 g_strdup (fields[j]));
496 }
497 g_hash_table_insert (params, g_strdup ("frequency"),
498 g_strdup (fields[1]));
499 break;
500 case 9: /* cable */
501 g_hash_table_insert (params, g_strdup ("type"), g_strdup ("cable"));
502 for (j = 2; j <= 5; j++) {
503 g_hash_table_insert (params, g_strdup (cable[j - 2]),
504 g_strdup (fields[j]));
505 }
506 g_hash_table_insert (params, g_strdup ("frequency"),
507 g_strdup (fields[1]));
508 break;
509 case 8: /* satellite */
510 g_hash_table_insert (params, g_strdup ("type"), g_strdup ("satellite"));
511 for (j = 2; j <= 4; j++) {
512 g_hash_table_insert (params, g_strdup (satellite[j - 2]),
513 g_strdup (fields[j]));
514 }
515 /* Some ZAP format variations store freqs in MHz
516 * but we internally use kHz for DVB-S/S2. */
517 if (strlen (fields[1]) < 6) {
518 g_hash_table_insert (params, g_strdup ("frequency"),
519 g_strdup_printf ("%d", atoi (fields[1]) * 1000));
520 } else {
521 g_hash_table_insert (params, g_strdup ("frequency"),
522 g_strdup_printf ("%d", atoi (fields[1])));
523 }
524 break;
525 case 6: /* atsc (vsb/qam) */
526 g_hash_table_insert (params, g_strdup ("type"), g_strdup ("atsc"));
527 g_hash_table_insert (params, g_strdup ("modulation"),
528 g_strdup (fields[2]));
529
530 g_hash_table_insert (params, g_strdup ("frequency"),
531 g_strdup (fields[1]));
532 break;
533 default:
534 goto not_parsed;
535 }
536
537 /* parsed */
538 g_hash_table_insert (params, g_strdup ("sid"),
539 g_strdup (fields[numfields - 1]));
540 g_hash_table_insert (res, g_strdup (fields[0]), params);
541 parsedchannels++;
542
543 not_parsed:
544 g_strfreev (fields);
545 next_line:
546 line = lines[++i];
547 }
548
549 g_strfreev (lines);
550 g_free (contents);
551
552 if (parsedchannels == 0)
553 goto no_channels;
554
555 return res;
556
557 open_fail:
558 if (err->code == G_FILE_ERROR_NOENT) {
559 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND,
560 _("Couldn't find channel configuration file: '%s'"), err->message);
561 } else {
562 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
563 _("Couldn't load channel configuration file: '%s'"), err->message);
564 }
565 g_clear_error (&err);
566 return NULL;
567
568 no_channels:
569 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
570 _("Channel configuration file doesn't contain any channels"));
571 g_hash_table_unref (res);
572 return NULL;
573 }
574
575 static gboolean
remove_channel_from_hash(gpointer key,gpointer value,gpointer user_data)576 remove_channel_from_hash (gpointer key, gpointer value, gpointer user_data)
577 {
578 g_free (key);
579 if (value)
580 g_hash_table_destroy ((GHashTable *) value);
581 return TRUE;
582 }
583
584 static void
destroy_channels_hash(GHashTable * channels)585 destroy_channels_hash (GHashTable * channels)
586 {
587 g_hash_table_foreach_remove (channels, remove_channel_from_hash, NULL);
588 }
589
590 /* FIXME: is channel_name guaranteed to be ASCII or UTF-8? */
591 static gboolean
parse_and_configure_from_zap_conf_file(GstElement * dvbbasebin,const gchar * filename,const gchar * channel_name,GError ** error)592 parse_and_configure_from_zap_conf_file (GstElement * dvbbasebin,
593 const gchar * filename, const gchar * channel_name, GError ** error)
594 {
595 gboolean ret = FALSE;
596 GHashTable *channels, *params;
597 gchar *type;
598
599 /* Assumptions are made here about a format that is loosely
600 * defined. Particularly, we assume a given delivery system
601 * out of counting the number of fields per line. dvbsrc has
602 * smarter code to auto-detect a delivery system based on
603 * known-correct combinations of parameters so if you ever
604 * encounter cases where the delivery system is being
605 * wrongly set here, just remove the offending
606 * g_object_set line and let dvbsrc work his magic out. */
607
608 channels = parse_channels_conf_from_zap_file (dvbbasebin, filename, error);
609
610 if (!channels)
611 goto beach;
612
613 params = g_hash_table_lookup (channels, channel_name);
614
615 if (!params)
616 goto unknown_channel;
617
618 g_object_set (dvbbasebin, "program-numbers",
619 g_hash_table_lookup (params, "sid"), NULL);
620 /* check if it is terrestrial or satellite */
621 g_object_set (dvbbasebin, "frequency",
622 atoi (g_hash_table_lookup (params, "frequency")), NULL);
623 type = g_hash_table_lookup (params, "type");
624 if (strcmp (type, "terrestrial") == 0) {
625 gchar *val;
626
627 val = g_hash_table_lookup (params, "inversion");
628 if (strcmp (val, "INVERSION_OFF") == 0)
629 g_object_set (dvbbasebin, "inversion", INVERSION_OFF, NULL);
630 else if (strcmp (val, "INVERSION_ON") == 0)
631 g_object_set (dvbbasebin, "inversion", INVERSION_ON, NULL);
632 else
633 g_object_set (dvbbasebin, "inversion", INVERSION_AUTO, NULL);
634
635 val = g_hash_table_lookup (params, "bandwidth");
636 if (strcmp (val, "BANDWIDTH_8_MHZ") == 0)
637 g_object_set (dvbbasebin, "bandwidth", 0, NULL);
638 else if (strcmp (val, "BANDWIDTH_7_MHZ") == 0)
639 g_object_set (dvbbasebin, "bandwidth", 1, NULL);
640 else if (strcmp (val, "BANDWIDTH_6_MHZ") == 0)
641 g_object_set (dvbbasebin, "bandwidth", 2, NULL);
642 else if (strcmp (val, "BANDWIDTH_5_MHZ") == 0)
643 g_object_set (dvbbasebin, "bandwidth", 4, NULL);
644 else if (strcmp (val, "BANDWIDTH_10_MHZ") == 0)
645 g_object_set (dvbbasebin, "bandwidth", 5, NULL);
646 else if (strcmp (val, "BANDWIDTH_1_712_MHZ") == 0)
647 g_object_set (dvbbasebin, "bandwidth", 6, NULL);
648 else
649 g_object_set (dvbbasebin, "bandwidth", 3, NULL);
650
651 val = g_hash_table_lookup (params, "code-rate-hp");
652 if (strcmp (val, "FEC_NONE") == 0)
653 g_object_set (dvbbasebin, "code-rate-hp", 0, NULL);
654 else if (strcmp (val, "FEC_1_2") == 0)
655 g_object_set (dvbbasebin, "code-rate-hp", 1, NULL);
656 else if (strcmp (val, "FEC_2_3") == 0)
657 g_object_set (dvbbasebin, "code-rate-hp", 2, NULL);
658 else if (strcmp (val, "FEC_3_4") == 0)
659 g_object_set (dvbbasebin, "code-rate-hp", 3, NULL);
660 else if (strcmp (val, "FEC_4_5") == 0)
661 g_object_set (dvbbasebin, "code-rate-hp", 4, NULL);
662 else if (strcmp (val, "FEC_5_6") == 0)
663 g_object_set (dvbbasebin, "code-rate-hp", 5, NULL);
664 else if (strcmp (val, "FEC_6_7") == 0)
665 g_object_set (dvbbasebin, "code-rate-hp", 6, NULL);
666 else if (strcmp (val, "FEC_7_8") == 0)
667 g_object_set (dvbbasebin, "code-rate-hp", 7, NULL);
668 else if (strcmp (val, "FEC_8_9") == 0)
669 g_object_set (dvbbasebin, "code-rate-hp", 8, NULL);
670 else
671 g_object_set (dvbbasebin, "code-rate-hp", 9, NULL);
672
673 val = g_hash_table_lookup (params, "code-rate-lp");
674 if (strcmp (val, "FEC_NONE") == 0)
675 g_object_set (dvbbasebin, "code-rate-lp", 0, NULL);
676 else if (strcmp (val, "FEC_1_2") == 0)
677 g_object_set (dvbbasebin, "code-rate-lp", 1, NULL);
678 else if (strcmp (val, "FEC_2_3") == 0)
679 g_object_set (dvbbasebin, "code-rate-lp", 2, NULL);
680 else if (strcmp (val, "FEC_3_4") == 0)
681 g_object_set (dvbbasebin, "code-rate-lp", 3, NULL);
682 else if (strcmp (val, "FEC_4_5") == 0)
683 g_object_set (dvbbasebin, "code-rate-lp", 4, NULL);
684 else if (strcmp (val, "FEC_5_6") == 0)
685 g_object_set (dvbbasebin, "code-rate-lp", 5, NULL);
686 else if (strcmp (val, "FEC_6_7") == 0)
687 g_object_set (dvbbasebin, "code-rate-lp", 6, NULL);
688 else if (strcmp (val, "FEC_7_8") == 0)
689 g_object_set (dvbbasebin, "code-rate-lp", 7, NULL);
690 else if (strcmp (val, "FEC_8_9") == 0)
691 g_object_set (dvbbasebin, "code-rate-lp", 8, NULL);
692 else
693 g_object_set (dvbbasebin, "code-rate-lp", 9, NULL);
694
695 val = g_hash_table_lookup (params, "modulation");
696 if (strcmp (val, "QPSK") == 0)
697 g_object_set (dvbbasebin, "modulation", 0, NULL);
698 else if (strcmp (val, "QAM_16") == 0)
699 g_object_set (dvbbasebin, "modulation", 1, NULL);
700 else if (strcmp (val, "QAM_32") == 0)
701 g_object_set (dvbbasebin, "modulation", 2, NULL);
702 else if (strcmp (val, "QAM_64") == 0)
703 g_object_set (dvbbasebin, "modulation", 3, NULL);
704 else if (strcmp (val, "QAM_128") == 0)
705 g_object_set (dvbbasebin, "modulation", 4, NULL);
706 else if (strcmp (val, "QAM_256") == 0)
707 g_object_set (dvbbasebin, "modulation", 5, NULL);
708 else
709 g_object_set (dvbbasebin, "modulation", 6, NULL);
710
711 val = g_hash_table_lookup (params, "transmission-mode");
712 if (strcmp (val, "TRANSMISSION_MODE_2K") == 0)
713 g_object_set (dvbbasebin, "trans-mode", 0, NULL);
714 else if (strcmp (val, "TRANSMISSION_MODE_8K") == 0)
715 g_object_set (dvbbasebin, "trans-mode", 1, NULL);
716 else
717 g_object_set (dvbbasebin, "trans-mode", 2, NULL);
718
719 val = g_hash_table_lookup (params, "guard");
720 if (strcmp (val, "GUARD_INTERVAL_1_32") == 0)
721 g_object_set (dvbbasebin, "guard", 0, NULL);
722 else if (strcmp (val, "GUARD_INTERVAL_1_16") == 0)
723 g_object_set (dvbbasebin, "guard", 1, NULL);
724 else if (strcmp (val, "GUARD_INTERVAL_1_8") == 0)
725 g_object_set (dvbbasebin, "guard", 2, NULL);
726 else if (strcmp (val, "GUARD_INTERVAL_1_4") == 0)
727 g_object_set (dvbbasebin, "guard", 3, NULL);
728 else
729 g_object_set (dvbbasebin, "guard", 4, NULL);
730
731 val = g_hash_table_lookup (params, "hierarchy");
732 if (strcmp (val, "HIERARCHY_NONE") == 0)
733 g_object_set (dvbbasebin, "hierarchy", 0, NULL);
734 else if (strcmp (val, "HIERARCHY_1") == 0)
735 g_object_set (dvbbasebin, "hierarchy", 1, NULL);
736 else if (strcmp (val, "HIERARCHY_2") == 0)
737 g_object_set (dvbbasebin, "hierarchy", 2, NULL);
738 else if (strcmp (val, "HIERARCHY_4") == 0)
739 g_object_set (dvbbasebin, "hierarchy", 3, NULL);
740 else
741 g_object_set (dvbbasebin, "hierarchy", 4, NULL);
742
743 ret = TRUE;
744 } else if (strcmp (type, "satellite") == 0) {
745 gchar *val;
746
747 ret = TRUE;
748
749 g_object_set (dvbbasebin, "delsys", SYS_DVBS, NULL);
750
751 val = g_hash_table_lookup (params, "polarity");
752 if (val)
753 g_object_set (dvbbasebin, "polarity", val, NULL);
754 else
755 ret = FALSE;
756
757 val = g_hash_table_lookup (params, "diseqc-source");
758 if (val)
759 g_object_set (dvbbasebin, "diseqc-source", atoi (val), NULL);
760
761 val = g_hash_table_lookup (params, "symbol-rate");
762 if (val)
763 g_object_set (dvbbasebin, "symbol-rate", atoi (val), NULL);
764 else
765 ret = FALSE;
766 } else if (strcmp (type, "cable") == 0) {
767 gchar *val;
768
769 g_object_set (dvbbasebin, "delsys", SYS_DVBC_ANNEX_A, NULL);
770
771 ret = TRUE;
772 val = g_hash_table_lookup (params, "symbol-rate");
773 if (val)
774 g_object_set (dvbbasebin, "symbol-rate", atoi (val) / 1000, NULL);
775 val = g_hash_table_lookup (params, "modulation");
776 if (strcmp (val, "QPSK") == 0)
777 g_object_set (dvbbasebin, "modulation", 0, NULL);
778 else if (strcmp (val, "QAM_16") == 0)
779 g_object_set (dvbbasebin, "modulation", 1, NULL);
780 else if (strcmp (val, "QAM_32") == 0)
781 g_object_set (dvbbasebin, "modulation", 2, NULL);
782 else if (strcmp (val, "QAM_64") == 0)
783 g_object_set (dvbbasebin, "modulation", 3, NULL);
784 else if (strcmp (val, "QAM_128") == 0)
785 g_object_set (dvbbasebin, "modulation", 4, NULL);
786 else if (strcmp (val, "QAM_256") == 0)
787 g_object_set (dvbbasebin, "modulation", 5, NULL);
788 else
789 g_object_set (dvbbasebin, "modulation", 6, NULL);
790 val = g_hash_table_lookup (params, "code-rate-hp");
791 if (strcmp (val, "FEC_NONE") == 0)
792 g_object_set (dvbbasebin, "code-rate-hp", 0, NULL);
793 else if (strcmp (val, "FEC_1_2") == 0)
794 g_object_set (dvbbasebin, "code-rate-hp", 1, NULL);
795 else if (strcmp (val, "FEC_2_3") == 0)
796 g_object_set (dvbbasebin, "code-rate-hp", 2, NULL);
797 else if (strcmp (val, "FEC_3_4") == 0)
798 g_object_set (dvbbasebin, "code-rate-hp", 3, NULL);
799 else if (strcmp (val, "FEC_4_5") == 0)
800 g_object_set (dvbbasebin, "code-rate-hp", 4, NULL);
801 else if (strcmp (val, "FEC_5_6") == 0)
802 g_object_set (dvbbasebin, "code-rate-hp", 5, NULL);
803 else if (strcmp (val, "FEC_6_7") == 0)
804 g_object_set (dvbbasebin, "code-rate-hp", 6, NULL);
805 else if (strcmp (val, "FEC_7_8") == 0)
806 g_object_set (dvbbasebin, "code-rate-hp", 7, NULL);
807 else if (strcmp (val, "FEC_8_9") == 0)
808 g_object_set (dvbbasebin, "code-rate-hp", 8, NULL);
809 else
810 g_object_set (dvbbasebin, "code-rate-hp", 9, NULL);
811 val = g_hash_table_lookup (params, "inversion");
812 if (strcmp (val, "INVERSION_OFF") == 0)
813 g_object_set (dvbbasebin, "inversion", 0, NULL);
814 else if (strcmp (val, "INVERSION_ON") == 0)
815 g_object_set (dvbbasebin, "inversion", 1, NULL);
816 else
817 g_object_set (dvbbasebin, "inversion", 2, NULL);
818 } else if (strcmp (type, "atsc") == 0) {
819 gchar *val;
820
821 ret = TRUE;
822
823 g_object_set (dvbbasebin, "delsys", SYS_ATSC, NULL);
824
825 val = g_hash_table_lookup (params, "modulation");
826 if (strcmp (val, "QAM_64") == 0)
827 g_object_set (dvbbasebin, "modulation", 3, NULL);
828 else if (strcmp (val, "QAM_256") == 0)
829 g_object_set (dvbbasebin, "modulation", 5, NULL);
830 else if (strcmp (val, "8VSB") == 0)
831 g_object_set (dvbbasebin, "modulation", 7, NULL);
832 else if (strcmp (val, "16VSB") == 0)
833 g_object_set (dvbbasebin, "modulation", 8, NULL);
834 else
835 ret = FALSE;
836 }
837
838 destroy_channels_hash (channels);
839
840 beach:
841 return ret;
842
843 unknown_channel:
844 {
845 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND,
846 _("Couldn't find details for channel '%s'"), channel_name);
847 destroy_channels_hash (channels);
848 return FALSE;
849 }
850 }
851
852 static GstDvbChannelConfFormat
detect_file_format(const gchar * filename)853 detect_file_format (const gchar * filename)
854 {
855 gchar *contents;
856 gchar **lines;
857 gchar **line;
858 GstDvbChannelConfFormat ret = CHANNEL_CONF_FORMAT_NONE;
859
860 if (!g_file_get_contents (filename, &contents, NULL, NULL))
861 return ret;
862
863 lines = g_strsplit (contents, "\n", 0);
864 line = lines;
865
866 while (*line) {
867 if (g_str_has_prefix (*line, "[") && g_str_has_suffix (*line, "]")) {
868 ret = CHANNEL_CONF_FORMAT_DVBV5;
869 break;
870 } else if (g_strrstr (*line, ":")) {
871 ret = CHANNEL_CONF_FORMAT_ZAP;
872 break;
873 }
874 line++;
875 }
876
877 g_strfreev (lines);
878 g_free (contents);
879 return ret;
880 }
881
882 gboolean
set_properties_for_channel(GstElement * dvbbasebin,const gchar * channel_name,GError ** error)883 set_properties_for_channel (GstElement * dvbbasebin,
884 const gchar * channel_name, GError ** error)
885 {
886 gboolean ret = FALSE;
887 gchar *filename;
888
889 filename = g_strdup (g_getenv ("GST_DVB_CHANNELS_CONF"));
890 if (filename == NULL) {
891 filename = g_build_filename (g_get_user_config_dir (),
892 "gstreamer-" GST_API_VERSION, "dvb-channels.conf", NULL);
893 }
894
895 switch (detect_file_format (filename)) {
896 case CHANNEL_CONF_FORMAT_DVBV5:
897 if (!parse_and_configure_from_v5_conf_file (dvbbasebin, filename,
898 channel_name, error)) {
899 GST_WARNING_OBJECT (dvbbasebin, "Problem finding information for "
900 "channel '%s' in configuration file '%s'", channel_name, filename);
901 } else {
902 GST_INFO_OBJECT (dvbbasebin, "Parsed libdvbv5 channel configuration "
903 "file");
904 ret = TRUE;
905 }
906 break;
907 case CHANNEL_CONF_FORMAT_ZAP:
908 if (!parse_and_configure_from_zap_conf_file (dvbbasebin, filename,
909 channel_name, error)) {
910 GST_WARNING_OBJECT (dvbbasebin, "Problem finding information for "
911 "channel '%s' in configuration file '%s'", channel_name, filename);
912 } else {
913 GST_INFO_OBJECT (dvbbasebin, "Parsed ZAP channel configuration file");
914 ret = TRUE;
915 }
916 break;
917 default:
918 GST_WARNING_OBJECT (dvbbasebin, "Unknown configuration file format. "
919 "Can not get parameters for channel");
920 }
921
922 g_free (filename);
923 return ret;
924 }
925