mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 02:31:03 +00:00
3e519937a1
This logic did not belong to the channel configuration parser (only used by dvbbasebin) but to dvbsrc, which is the element directly using this value and honoring the "adapter" property. Allows previously non-working cases like this to work: GST_DVB_ADAPTER=1 gst-launch-1.0 dvbsrc delsys=11 modulation=7 frequency=689000000 ! fakesink
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;
|
|
}
|