mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-09 13:48:55 +00:00
924 lines
31 KiB
C
924 lines
31 KiB
C
/*
|
|
* 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;
|
|
|
|
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);
|
|
}
|
|
|
|
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, "Problem finding information for "
|
|
"channel '%s' in configuration file '%s'", channel_name, 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, "Problem finding information for "
|
|
"channel '%s' in configuration file '%s'", channel_name, 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;
|
|
}
|