| /* |
| * parsechannels.c - |
| * Copyright (C) 2008 Zaheer Abbas Merali |
| * |
| * Authors: |
| * Zaheer Abbas Merali <zaheerabbas at merali dot org> |
| * |
| * 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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <glib.h> |
| #include <glib-object.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <gst/gst.h> |
| |
| #include <gst/gst-i18n-plugin.h> |
| |
| #include "parsechannels.h" |
| |
| #include <linux/dvb/frontend.h> |
| |
| GST_DEBUG_CATEGORY_EXTERN (dvb_base_bin_debug); |
| #define GST_CAT_DEFAULT dvb_base_bin_debug |
| |
| typedef enum |
| { |
| CHANNEL_CONF_FORMAT_NONE, |
| CHANNEL_CONF_FORMAT_DVBV5, |
| CHANNEL_CONF_FORMAT_ZAP |
| } GstDvbChannelConfFormat; |
| |
| typedef gboolean (*GstDvbV5ChannelsConfPropSetFunction) (GstElement * |
| dvbbasebin, const gchar * property, GKeyFile * kf, |
| const gchar * channel_name, const gchar * key); |
| |
| typedef struct |
| { |
| const gchar *conf_property; |
| const gchar *elem_property; |
| GstDvbV5ChannelsConfPropSetFunction set_func; |
| } GstDvbV5ChannelsConfToPropertyMap; |
| |
| static gboolean parse_and_configure_from_v5_conf_file (GstElement * dvbbasebin, |
| const gchar * filename, const gchar * channel_name, GError ** error); |
| static gboolean parse_and_configure_from_zap_conf_file (GstElement * dvbbasebin, |
| const gchar * filename, const gchar * channel_name, GError ** error); |
| static GstDvbChannelConfFormat detect_file_format (const gchar * filename); |
| |
| static gboolean gst_dvb_base_bin_conf_set_string (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_uint (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_int (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_inversion (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_guard (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_trans_mode (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_code_rate (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_delsys (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_hierarchy (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static gboolean gst_dvb_base_bin_conf_set_modulation (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key); |
| static GHashTable *parse_channels_conf_from_zap_file (GstElement * dvbbasebin, |
| const gchar * filename, GError ** error); |
| static gboolean remove_channel_from_hash (gpointer key, gpointer value, |
| gpointer user_data); |
| static void destroy_channels_hash (GHashTable * channels); |
| |
| GstDvbV5ChannelsConfToPropertyMap dvbv5_prop_map[] = { |
| {"SERVICE_ID", "program-numbers", gst_dvb_base_bin_conf_set_string}, |
| {"FREQUENCY", "frequency", gst_dvb_base_bin_conf_set_uint}, |
| {"BANDWIDTH_HZ", "bandwidth-hz", gst_dvb_base_bin_conf_set_uint}, |
| {"INVERSION", "inversion", gst_dvb_base_bin_conf_set_inversion}, |
| {"GUARD_INTERVAL", "guard", gst_dvb_base_bin_conf_set_guard}, |
| {"TRANSMISSION_MODE", "trans-mode", gst_dvb_base_bin_conf_set_trans_mode}, |
| {"HIERARCHY", "hierarchy", gst_dvb_base_bin_conf_set_hierarchy}, |
| {"MODULATION", "modulation", gst_dvb_base_bin_conf_set_modulation}, |
| {"CODE_RATE_HP", "code-rate-hp", gst_dvb_base_bin_conf_set_code_rate}, |
| {"CODE_RATE_LP", "code-rate-lp", gst_dvb_base_bin_conf_set_code_rate}, |
| {"ISDBT_LAYER_ENABLED", "isdbt-layer-enabled", |
| gst_dvb_base_bin_conf_set_uint}, |
| {"ISDBT_PARTIAL_RECEPTION", "isdbt-partial-reception", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_SOUND_BROADCASTING", "isdbt-sound-broadcasting", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_SB_SUBCHANNEL_ID", "isdbt-sb-subchannel-id", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_SB_SEGMENT_IDX", "isdbt-sb-segment-idx", |
| gst_dvb_base_bin_conf_set_int}, |
| {"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 */ |
| {"ISDBT_LAYERA_FEC", "isdbt-layera-fec", gst_dvb_base_bin_conf_set_code_rate}, |
| {"ISDBT_LAYERA_MODULATION", "isdbt-layera-modulation", |
| gst_dvb_base_bin_conf_set_modulation}, |
| {"ISDBT_LAYERA_SEGMENT_COUNT", "isdbt-layera-segment-count", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_LAYERA_TIME_INTERLEAVING", "isdbt-layera-time-interleaving", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_LAYERB_FEC", "isdbt-layerb-fec", gst_dvb_base_bin_conf_set_code_rate}, |
| {"ISDBT_LAYERB_MODULATION", "isdbt-layerb-modulation", |
| gst_dvb_base_bin_conf_set_modulation}, |
| {"ISDBT_LAYERB_SEGMENT_COUNT", "isdbt-layerb-segment-count", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_LAYERB_TIME_INTERLEAVING", "isdbt-layerb-time-interleaving", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_LAYERC_FEC", "isdbt-layerc-fec", gst_dvb_base_bin_conf_set_code_rate}, |
| {"ISDBT_LAYERC_MODULATION", "isdbt-layerc-modulation", |
| gst_dvb_base_bin_conf_set_modulation}, |
| {"ISDBT_LAYERC_SEGMENT_COUNT", "isdbt-layerc-segment-count", |
| gst_dvb_base_bin_conf_set_int}, |
| {"ISDBT_LAYERC_TIME_INTERLEAVING", "isdbt-layerc-time-interleaving", |
| gst_dvb_base_bin_conf_set_int}, |
| {"DELIVERY_SYSTEM", "delsys", gst_dvb_base_bin_conf_set_delsys}, |
| {NULL,} |
| }; |
| |
| /* TODO: |
| * Store the channels hash table around instead of constantly parsing it |
| * Detect when the file changed on disk |
| */ |
| |
| static gint |
| gst_dvb_base_bin_find_string_in_array (const gchar ** array, const gchar * str) |
| { |
| gint i = 0; |
| const gchar *cur; |
| while ((cur = array[i])) { |
| if (strcmp (cur, str) == 0) |
| return i; |
| |
| i++; |
| } |
| |
| return -1; |
| } |
| |
| 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) |
| { |
| gchar *str; |
| gint v; |
| |
| str = g_key_file_get_string (kf, channel_name, key, NULL); |
| v = gst_dvb_base_bin_find_string_in_array (strings, str); |
| if (v == -1) { |
| GST_WARNING_OBJECT (dvbbasebin, "Unexpected value '%s' for property " |
| "'%s', using default: '%d'", str, property, default_value); |
| v = default_value; |
| } |
| |
| g_free (str); |
| g_object_set (dvbbasebin, property, v, NULL); |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_string (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| gchar *str; |
| |
| str = g_key_file_get_string (kf, channel_name, key, NULL); |
| if (!str) { |
| GST_WARNING_OBJECT (dvbbasebin, |
| "Could not get value for '%s' on channel '%s'", key, channel_name); |
| return FALSE; |
| } |
| |
| g_object_set (dvbbasebin, property, str, NULL); |
| g_free (str); |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_uint (GstElement * dvbbasebin, const gchar * property, |
| GKeyFile * kf, const gchar * channel_name, const gchar * key) |
| { |
| guint64 v; |
| |
| v = g_key_file_get_uint64 (kf, channel_name, key, NULL); |
| if (!v) { |
| GST_WARNING_OBJECT (dvbbasebin, |
| "Could not get value for '%s' on channel '%s'", key, channel_name); |
| return FALSE; |
| } |
| |
| g_object_set (dvbbasebin, property, (guint) v, NULL); |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_int (GstElement * dvbbasebin, const gchar * property, |
| GKeyFile * kf, const gchar * channel_name, const gchar * key) |
| { |
| gint v; |
| |
| v = g_key_file_get_integer (kf, channel_name, key, NULL); |
| if (!v) { |
| GST_WARNING_OBJECT (dvbbasebin, |
| "Could not get value for '%s' on channel '%s'", key, channel_name); |
| return FALSE; |
| } |
| |
| g_object_set (dvbbasebin, property, v, NULL); |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_inversion (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| gchar *str; |
| gint v; |
| |
| str = g_key_file_get_string (kf, channel_name, key, NULL); |
| if (!str) { |
| GST_WARNING_OBJECT (dvbbasebin, |
| "Could not get value for '%s' on channel '%s'", key, channel_name); |
| return FALSE; |
| } |
| |
| if (strcmp (str, "AUTO") == 0) |
| v = 2; |
| else if (strcmp (str, "ON") == 0) |
| v = 1; |
| else |
| v = 0; /* OFF */ |
| |
| g_free (str); |
| g_object_set (dvbbasebin, property, v, NULL); |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_guard (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| const gchar *guards[] = { |
| "1/32", "1/16", "1/8", "1/4", "auto", |
| "1/128", "19/128", "19/256", |
| "PN420", "PN595", "PN945", NULL |
| }; |
| return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin, |
| property, kf, channel_name, key, guards, 4); |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_trans_mode (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| const gchar *trans_modes[] = { |
| "2K", "8K", "AUTO", "4K", "1K", |
| "16K", "32K", "C1", "C3780", NULL |
| }; |
| return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin, |
| property, kf, channel_name, key, trans_modes, 2); |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_code_rate (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| const gchar *code_rates[] = { |
| "NONE", "1/2", "2/3", "3/4", "4/5", |
| "5/6", "6/7", "7/8", "8/9", "AUTO", |
| "3/5", "9/10", "2/5", NULL |
| }; |
| return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin, |
| property, kf, channel_name, key, code_rates, 9); |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_delsys (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| const gchar *delsys[] = { |
| "UNDEFINED", "DVBCA", "DVBCB", "DVBT", "DSS", |
| "DVBS", "DVBS2", "DVBH", "ISDBT", "ISDBS", |
| "ISDBC", "ATSC", "ATSCMH", "DTMB", "CMMB", |
| "DAB", "DVBT2", "TURBO", "DVBCC", NULL |
| }; |
| return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin, |
| property, kf, channel_name, key, delsys, 0); |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_hierarchy (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| const gchar *hierarchies[] = { |
| "NONE", "1", "2", "4", "AUTO", NULL |
| }; |
| return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin, |
| property, kf, channel_name, key, hierarchies, 4); |
| } |
| |
| static gboolean |
| gst_dvb_base_bin_conf_set_modulation (GstElement * dvbbasebin, |
| const gchar * property, GKeyFile * kf, const gchar * channel_name, |
| const gchar * key) |
| { |
| const gchar *modulations[] = { |
| "QPSK", "QAM/16", "QAM/32", "QAM/64", |
| "QAM/128", "QAM/256", "QAM/AUTO", "VSB/8", |
| "VSB/16", "PSK/8", "APSK/16", "APSK/32", |
| "DQPSK", "QAM/4_NR", NULL |
| }; |
| return gst_dvb_base_bin_conf_set_property_from_string_array (dvbbasebin, |
| property, kf, channel_name, key, modulations, 6); |
| } |
| |
| /* FIXME: is channel_name guaranteed to be ASCII or UTF-8? */ |
| static gboolean |
| parse_and_configure_from_v5_conf_file (GstElement * dvbbasebin, |
| const gchar * filename, const gchar * channel_name, GError ** error) |
| { |
| GKeyFile *keyfile; |
| gchar **keys, **keys_p; |
| GError *err = NULL; |
| |
| keyfile = g_key_file_new (); |
| if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &err)) |
| goto load_error; |
| |
| if (!g_key_file_has_group (keyfile, channel_name)) |
| goto unknown_channel; |
| |
| keys = g_key_file_get_keys (keyfile, channel_name, NULL, &err); |
| if (!keys) |
| goto no_properties; |
| |
| keys_p = keys; |
| while (*keys_p) { |
| const gchar *k = *keys_p; |
| const GstDvbV5ChannelsConfToPropertyMap *map_entry = dvbv5_prop_map; |
| gboolean property_found = FALSE; |
| |
| GST_LOG_OBJECT (dvbbasebin, "Setting property %s", k); |
| |
| while (map_entry->conf_property) { |
| if (strcmp (map_entry->conf_property, k) == 0) { |
| if (!map_entry->set_func (dvbbasebin, map_entry->elem_property, keyfile, |
| channel_name, k)) |
| goto property_error; |
| property_found = TRUE; |
| break; |
| } |
| map_entry++; |
| } |
| |
| if (!property_found) |
| GST_WARNING_OBJECT (dvbbasebin, "Failed to map property '%s'", k); |
| |
| keys_p++; |
| } |
| |
| GST_DEBUG_OBJECT (dvbbasebin, "Successfully parsed channel configuration " |
| "file '%s'", filename); |
| g_strfreev (keys); |
| g_key_file_unref (keyfile); |
| return TRUE; |
| |
| load_error: |
| if ((err->domain == G_FILE_ERROR && err->code == G_FILE_ERROR_NOENT) || |
| (err->domain == G_KEY_FILE_ERROR |
| && err->code == G_KEY_FILE_ERROR_NOT_FOUND)) { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, |
| _("Couldn't find channel configuration file")); |
| } else { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ, |
| _("Couldn't load channel configuration file: '%s'"), err->message); |
| } |
| g_clear_error (&err); |
| return FALSE; |
| |
| unknown_channel: |
| { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, |
| _("Couldn't find details for channel '%s'"), channel_name); |
| g_key_file_unref (keyfile); |
| g_clear_error (&err); |
| return FALSE; |
| } |
| |
| no_properties: |
| { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, |
| _("No properties for channel '%s'"), channel_name); |
| g_key_file_unref (keyfile); |
| g_clear_error (&err); |
| return FALSE; |
| } |
| |
| property_error: |
| { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED, |
| _("Failed to set properties for channel '%s'"), channel_name); |
| g_key_file_unref (keyfile); |
| g_clear_error (&err); |
| return FALSE; |
| } |
| } |
| |
| static GHashTable * |
| parse_channels_conf_from_zap_file (GstElement * dvbbasebin, |
| const gchar * filename, GError ** error) |
| { |
| gchar *contents; |
| gchar **lines; |
| gchar *line; |
| gchar **fields; |
| int i, parsedchannels = 0; |
| GHashTable *res; |
| GError *err = NULL; |
| const gchar *terrestrial[] = { "inversion", "bandwidth", |
| "code-rate-hp", "code-rate-lp", "modulation", "transmission-mode", |
| "guard", "hierarchy" |
| }; |
| const gchar *satellite[] = { "polarity", "diseqc-source", |
| "symbol-rate" |
| }; |
| const gchar *cable[] = { "inversion", "symbol-rate", "code-rate-hp", |
| "modulation" |
| }; |
| |
| GST_INFO_OBJECT (dvbbasebin, "parsing '%s'", filename); |
| |
| if (!g_file_get_contents (filename, &contents, NULL, &err)) |
| goto open_fail; |
| |
| lines = g_strsplit (contents, "\n", 0); |
| res = g_hash_table_new (g_str_hash, g_str_equal); |
| |
| i = 0; |
| line = lines[0]; |
| while (line != NULL) { |
| GHashTable *params; |
| int j, numfields; |
| |
| if (line[0] == '#') |
| goto next_line; |
| |
| params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); |
| fields = g_strsplit (line, ":", 0); |
| numfields = g_strv_length (fields); |
| |
| switch (numfields) { |
| case 13: /* terrestrial */ |
| g_hash_table_insert (params, g_strdup ("type"), |
| g_strdup ("terrestrial")); |
| for (j = 2; j <= 9; j++) { |
| g_hash_table_insert (params, g_strdup (terrestrial[j - 2]), |
| g_strdup (fields[j])); |
| } |
| g_hash_table_insert (params, g_strdup ("frequency"), |
| g_strdup (fields[1])); |
| break; |
| case 9: /* cable */ |
| g_hash_table_insert (params, g_strdup ("type"), g_strdup ("cable")); |
| for (j = 2; j <= 5; j++) { |
| g_hash_table_insert (params, g_strdup (cable[j - 2]), |
| g_strdup (fields[j])); |
| } |
| g_hash_table_insert (params, g_strdup ("frequency"), |
| g_strdup (fields[1])); |
| break; |
| case 8: /* satellite */ |
| g_hash_table_insert (params, g_strdup ("type"), g_strdup ("satellite")); |
| for (j = 2; j <= 4; j++) { |
| g_hash_table_insert (params, g_strdup (satellite[j - 2]), |
| g_strdup (fields[j])); |
| } |
| /* Some ZAP format variations store freqs in MHz |
| * but we internally use kHz for DVB-S/S2. */ |
| if (strlen (fields[1]) < 6) { |
| g_hash_table_insert (params, g_strdup ("frequency"), |
| g_strdup_printf ("%d", atoi (fields[1]) * 1000)); |
| } else { |
| g_hash_table_insert (params, g_strdup ("frequency"), |
| g_strdup_printf ("%d", atoi (fields[1]))); |
| } |
| break; |
| case 6: /* atsc (vsb/qam) */ |
| g_hash_table_insert (params, g_strdup ("type"), g_strdup ("atsc")); |
| g_hash_table_insert (params, g_strdup ("modulation"), |
| g_strdup (fields[2])); |
| |
| g_hash_table_insert (params, g_strdup ("frequency"), |
| g_strdup (fields[1])); |
| break; |
| default: |
| goto not_parsed; |
| } |
| |
| /* parsed */ |
| g_hash_table_insert (params, g_strdup ("sid"), |
| g_strdup (fields[numfields - 1])); |
| g_hash_table_insert (res, g_strdup (fields[0]), params); |
| parsedchannels++; |
| |
| not_parsed: |
| g_strfreev (fields); |
| next_line: |
| line = lines[++i]; |
| } |
| |
| g_strfreev (lines); |
| g_free (contents); |
| |
| if (parsedchannels == 0) |
| goto no_channels; |
| |
| return res; |
| |
| open_fail: |
| if (err->code == G_FILE_ERROR_NOENT) { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, |
| _("Couldn't find channel configuration file: '%s'"), err->message); |
| } else { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ, |
| _("Couldn't load channel configuration file: '%s'"), err->message); |
| } |
| g_clear_error (&err); |
| return NULL; |
| |
| no_channels: |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED, |
| _("Channel configuration file doesn't contain any channels")); |
| g_hash_table_unref (res); |
| return NULL; |
| } |
| |
| static gboolean |
| remove_channel_from_hash (gpointer key, gpointer value, gpointer user_data) |
| { |
| g_free (key); |
| if (value) |
| g_hash_table_destroy ((GHashTable *) value); |
| return TRUE; |
| } |
| |
| static void |
| destroy_channels_hash (GHashTable * channels) |
| { |
| g_hash_table_foreach_remove (channels, remove_channel_from_hash, NULL); |
| } |
| |
| /* FIXME: is channel_name guaranteed to be ASCII or UTF-8? */ |
| static gboolean |
| parse_and_configure_from_zap_conf_file (GstElement * dvbbasebin, |
| const gchar * filename, const gchar * channel_name, GError ** error) |
| { |
| gboolean ret = FALSE; |
| GHashTable *channels, *params; |
| gchar *type; |
| |
| /* Assumptions are made here about a format that is loosely |
| * defined. Particularly, we assume a given delivery system |
| * out of counting the number of fields per line. dvbsrc has |
| * smarter code to auto-detect a delivery system based on |
| * known-correct combinations of parameters so if you ever |
| * encounter cases where the delivery system is being |
| * wrongly set here, just remove the offending |
| * g_object_set line and let dvbsrc work his magic out. */ |
| |
| channels = parse_channels_conf_from_zap_file (dvbbasebin, filename, error); |
| |
| if (!channels) |
| goto beach; |
| |
| params = g_hash_table_lookup (channels, channel_name); |
| |
| if (!params) |
| goto unknown_channel; |
| |
| g_object_set (dvbbasebin, "program-numbers", |
| g_hash_table_lookup (params, "sid"), NULL); |
| /* check if it is terrestrial or satellite */ |
| g_object_set (dvbbasebin, "frequency", |
| atoi (g_hash_table_lookup (params, "frequency")), NULL); |
| type = g_hash_table_lookup (params, "type"); |
| if (strcmp (type, "terrestrial") == 0) { |
| gchar *val; |
| |
| val = g_hash_table_lookup (params, "inversion"); |
| if (strcmp (val, "INVERSION_OFF") == 0) |
| g_object_set (dvbbasebin, "inversion", INVERSION_OFF, NULL); |
| else if (strcmp (val, "INVERSION_ON") == 0) |
| g_object_set (dvbbasebin, "inversion", INVERSION_ON, NULL); |
| else |
| g_object_set (dvbbasebin, "inversion", INVERSION_AUTO, NULL); |
| |
| val = g_hash_table_lookup (params, "bandwidth"); |
| if (strcmp (val, "BANDWIDTH_8_MHZ") == 0) |
| g_object_set (dvbbasebin, "bandwidth", 0, NULL); |
| else if (strcmp (val, "BANDWIDTH_7_MHZ") == 0) |
| g_object_set (dvbbasebin, "bandwidth", 1, NULL); |
| else if (strcmp (val, "BANDWIDTH_6_MHZ") == 0) |
| g_object_set (dvbbasebin, "bandwidth", 2, NULL); |
| else if (strcmp (val, "BANDWIDTH_5_MHZ") == 0) |
| g_object_set (dvbbasebin, "bandwidth", 4, NULL); |
| else if (strcmp (val, "BANDWIDTH_10_MHZ") == 0) |
| g_object_set (dvbbasebin, "bandwidth", 5, NULL); |
| else if (strcmp (val, "BANDWIDTH_1_712_MHZ") == 0) |
| g_object_set (dvbbasebin, "bandwidth", 6, NULL); |
| else |
| g_object_set (dvbbasebin, "bandwidth", 3, NULL); |
| |
| val = g_hash_table_lookup (params, "code-rate-hp"); |
| if (strcmp (val, "FEC_NONE") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 0, NULL); |
| else if (strcmp (val, "FEC_1_2") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 1, NULL); |
| else if (strcmp (val, "FEC_2_3") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 2, NULL); |
| else if (strcmp (val, "FEC_3_4") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 3, NULL); |
| else if (strcmp (val, "FEC_4_5") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 4, NULL); |
| else if (strcmp (val, "FEC_5_6") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 5, NULL); |
| else if (strcmp (val, "FEC_6_7") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 6, NULL); |
| else if (strcmp (val, "FEC_7_8") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 7, NULL); |
| else if (strcmp (val, "FEC_8_9") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 8, NULL); |
| else |
| g_object_set (dvbbasebin, "code-rate-hp", 9, NULL); |
| |
| val = g_hash_table_lookup (params, "code-rate-lp"); |
| if (strcmp (val, "FEC_NONE") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 0, NULL); |
| else if (strcmp (val, "FEC_1_2") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 1, NULL); |
| else if (strcmp (val, "FEC_2_3") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 2, NULL); |
| else if (strcmp (val, "FEC_3_4") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 3, NULL); |
| else if (strcmp (val, "FEC_4_5") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 4, NULL); |
| else if (strcmp (val, "FEC_5_6") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 5, NULL); |
| else if (strcmp (val, "FEC_6_7") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 6, NULL); |
| else if (strcmp (val, "FEC_7_8") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 7, NULL); |
| else if (strcmp (val, "FEC_8_9") == 0) |
| g_object_set (dvbbasebin, "code-rate-lp", 8, NULL); |
| else |
| g_object_set (dvbbasebin, "code-rate-lp", 9, NULL); |
| |
| val = g_hash_table_lookup (params, "modulation"); |
| if (strcmp (val, "QPSK") == 0) |
| g_object_set (dvbbasebin, "modulation", 0, NULL); |
| else if (strcmp (val, "QAM_16") == 0) |
| g_object_set (dvbbasebin, "modulation", 1, NULL); |
| else if (strcmp (val, "QAM_32") == 0) |
| g_object_set (dvbbasebin, "modulation", 2, NULL); |
| else if (strcmp (val, "QAM_64") == 0) |
| g_object_set (dvbbasebin, "modulation", 3, NULL); |
| else if (strcmp (val, "QAM_128") == 0) |
| g_object_set (dvbbasebin, "modulation", 4, NULL); |
| else if (strcmp (val, "QAM_256") == 0) |
| g_object_set (dvbbasebin, "modulation", 5, NULL); |
| else |
| g_object_set (dvbbasebin, "modulation", 6, NULL); |
| |
| val = g_hash_table_lookup (params, "transmission-mode"); |
| if (strcmp (val, "TRANSMISSION_MODE_2K") == 0) |
| g_object_set (dvbbasebin, "trans-mode", 0, NULL); |
| else if (strcmp (val, "TRANSMISSION_MODE_8K") == 0) |
| g_object_set (dvbbasebin, "trans-mode", 1, NULL); |
| else |
| g_object_set (dvbbasebin, "trans-mode", 2, NULL); |
| |
| val = g_hash_table_lookup (params, "guard"); |
| if (strcmp (val, "GUARD_INTERVAL_1_32") == 0) |
| g_object_set (dvbbasebin, "guard", 0, NULL); |
| else if (strcmp (val, "GUARD_INTERVAL_1_16") == 0) |
| g_object_set (dvbbasebin, "guard", 1, NULL); |
| else if (strcmp (val, "GUARD_INTERVAL_1_8") == 0) |
| g_object_set (dvbbasebin, "guard", 2, NULL); |
| else if (strcmp (val, "GUARD_INTERVAL_1_4") == 0) |
| g_object_set (dvbbasebin, "guard", 3, NULL); |
| else |
| g_object_set (dvbbasebin, "guard", 4, NULL); |
| |
| val = g_hash_table_lookup (params, "hierarchy"); |
| if (strcmp (val, "HIERARCHY_NONE") == 0) |
| g_object_set (dvbbasebin, "hierarchy", 0, NULL); |
| else if (strcmp (val, "HIERARCHY_1") == 0) |
| g_object_set (dvbbasebin, "hierarchy", 1, NULL); |
| else if (strcmp (val, "HIERARCHY_2") == 0) |
| g_object_set (dvbbasebin, "hierarchy", 2, NULL); |
| else if (strcmp (val, "HIERARCHY_4") == 0) |
| g_object_set (dvbbasebin, "hierarchy", 3, NULL); |
| else |
| g_object_set (dvbbasebin, "hierarchy", 4, NULL); |
| |
| ret = TRUE; |
| } else if (strcmp (type, "satellite") == 0) { |
| gchar *val; |
| |
| ret = TRUE; |
| |
| g_object_set (dvbbasebin, "delsys", SYS_DVBS, NULL); |
| |
| val = g_hash_table_lookup (params, "polarity"); |
| if (val) |
| g_object_set (dvbbasebin, "polarity", val, NULL); |
| else |
| ret = FALSE; |
| |
| val = g_hash_table_lookup (params, "diseqc-source"); |
| if (val) |
| g_object_set (dvbbasebin, "diseqc-source", atoi (val), NULL); |
| |
| val = g_hash_table_lookup (params, "symbol-rate"); |
| if (val) |
| g_object_set (dvbbasebin, "symbol-rate", atoi (val), NULL); |
| else |
| ret = FALSE; |
| } else if (strcmp (type, "cable") == 0) { |
| gchar *val; |
| |
| g_object_set (dvbbasebin, "delsys", SYS_DVBC_ANNEX_A, NULL); |
| |
| ret = TRUE; |
| val = g_hash_table_lookup (params, "symbol-rate"); |
| if (val) |
| g_object_set (dvbbasebin, "symbol-rate", atoi (val) / 1000, NULL); |
| val = g_hash_table_lookup (params, "modulation"); |
| if (strcmp (val, "QPSK") == 0) |
| g_object_set (dvbbasebin, "modulation", 0, NULL); |
| else if (strcmp (val, "QAM_16") == 0) |
| g_object_set (dvbbasebin, "modulation", 1, NULL); |
| else if (strcmp (val, "QAM_32") == 0) |
| g_object_set (dvbbasebin, "modulation", 2, NULL); |
| else if (strcmp (val, "QAM_64") == 0) |
| g_object_set (dvbbasebin, "modulation", 3, NULL); |
| else if (strcmp (val, "QAM_128") == 0) |
| g_object_set (dvbbasebin, "modulation", 4, NULL); |
| else if (strcmp (val, "QAM_256") == 0) |
| g_object_set (dvbbasebin, "modulation", 5, NULL); |
| else |
| g_object_set (dvbbasebin, "modulation", 6, NULL); |
| val = g_hash_table_lookup (params, "code-rate-hp"); |
| if (strcmp (val, "FEC_NONE") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 0, NULL); |
| else if (strcmp (val, "FEC_1_2") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 1, NULL); |
| else if (strcmp (val, "FEC_2_3") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 2, NULL); |
| else if (strcmp (val, "FEC_3_4") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 3, NULL); |
| else if (strcmp (val, "FEC_4_5") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 4, NULL); |
| else if (strcmp (val, "FEC_5_6") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 5, NULL); |
| else if (strcmp (val, "FEC_6_7") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 6, NULL); |
| else if (strcmp (val, "FEC_7_8") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 7, NULL); |
| else if (strcmp (val, "FEC_8_9") == 0) |
| g_object_set (dvbbasebin, "code-rate-hp", 8, NULL); |
| else |
| g_object_set (dvbbasebin, "code-rate-hp", 9, NULL); |
| val = g_hash_table_lookup (params, "inversion"); |
| if (strcmp (val, "INVERSION_OFF") == 0) |
| g_object_set (dvbbasebin, "inversion", 0, NULL); |
| else if (strcmp (val, "INVERSION_ON") == 0) |
| g_object_set (dvbbasebin, "inversion", 1, NULL); |
| else |
| g_object_set (dvbbasebin, "inversion", 2, NULL); |
| } else if (strcmp (type, "atsc") == 0) { |
| gchar *val; |
| |
| ret = TRUE; |
| |
| g_object_set (dvbbasebin, "delsys", SYS_ATSC, NULL); |
| |
| val = g_hash_table_lookup (params, "modulation"); |
| if (strcmp (val, "QAM_64") == 0) |
| g_object_set (dvbbasebin, "modulation", 3, NULL); |
| else if (strcmp (val, "QAM_256") == 0) |
| g_object_set (dvbbasebin, "modulation", 5, NULL); |
| else if (strcmp (val, "8VSB") == 0) |
| g_object_set (dvbbasebin, "modulation", 7, NULL); |
| else if (strcmp (val, "16VSB") == 0) |
| g_object_set (dvbbasebin, "modulation", 8, NULL); |
| else |
| ret = FALSE; |
| } |
| |
| destroy_channels_hash (channels); |
| |
| beach: |
| return ret; |
| |
| unknown_channel: |
| { |
| g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, |
| _("Couldn't find details for channel '%s'"), channel_name); |
| destroy_channels_hash (channels); |
| return FALSE; |
| } |
| } |
| |
| static GstDvbChannelConfFormat |
| detect_file_format (const gchar * filename) |
| { |
| gchar *contents; |
| gchar **lines; |
| gchar **line; |
| GstDvbChannelConfFormat ret = CHANNEL_CONF_FORMAT_NONE; |
| |
| if (!g_file_get_contents (filename, &contents, NULL, NULL)) |
| return ret; |
| |
| lines = g_strsplit (contents, "\n", 0); |
| line = lines; |
| |
| while (*line) { |
| if (g_str_has_prefix (*line, "[") && g_str_has_suffix (*line, "]")) { |
| ret = CHANNEL_CONF_FORMAT_DVBV5; |
| break; |
| } else if (g_strrstr (*line, ":")) { |
| ret = CHANNEL_CONF_FORMAT_ZAP; |
| break; |
| } |
| line++; |
| } |
| |
| g_strfreev (lines); |
| g_free (contents); |
| return ret; |
| } |
| |
| gboolean |
| set_properties_for_channel (GstElement * dvbbasebin, |
| const gchar * channel_name, GError ** error) |
| { |
| gboolean ret = FALSE; |
| gchar *filename; |
| const gchar *adapter; |
| |
| filename = g_strdup (g_getenv ("GST_DVB_CHANNELS_CONF")); |
| if (filename == NULL) { |
| filename = g_build_filename (g_get_user_config_dir (), |
| "gstreamer-" GST_API_VERSION, "dvb-channels.conf", NULL); |
| } |
| |
| adapter = g_getenv ("GST_DVB_ADAPTER"); |
| if (adapter) |
| g_object_set (dvbbasebin, "adapter", atoi (adapter), NULL); |
| |
| switch (detect_file_format (filename)) { |
| case CHANNEL_CONF_FORMAT_DVBV5: |
| if (!parse_and_configure_from_v5_conf_file (dvbbasebin, filename, |
| channel_name, error)) { |
| GST_WARNING_OBJECT (dvbbasebin, "Could not parse libdvbv5 channel " |
| "configuration file '%s'", filename); |
| } else { |
| GST_INFO_OBJECT (dvbbasebin, "Parsed libdvbv5 channel configuration " |
| "file"); |
| ret = TRUE; |
| } |
| break; |
| case CHANNEL_CONF_FORMAT_ZAP: |
| if (!parse_and_configure_from_zap_conf_file (dvbbasebin, filename, |
| channel_name, error)) { |
| GST_WARNING_OBJECT (dvbbasebin, "Could not parse ZAP channel " |
| "configuration file '%s'", filename); |
| } else { |
| GST_INFO_OBJECT (dvbbasebin, "Parsed ZAP channel configuration file"); |
| ret = TRUE; |
| } |
| break; |
| default: |
| GST_WARNING_OBJECT (dvbbasebin, "Unknown configuration file format. " |
| "Can not get parameters for channel"); |
| } |
| |
| g_free (filename); |
| return ret; |
| } |