gstreamer/sys/dvb/gstdvbsrc.c
Reynaldo H. Verdejo Pinochet 768b0c2696 dvbsrc: avoid redundant delsys querying
There is no need to query the frontend for the list
of supported delivery systems if we are selecting
one from the list of autodetected ones.
2016-04-12 15:08:29 -07:00

2649 lines
89 KiB
C

/* GStreamer DVB source
* Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali
* dot org>
* Copyright (C) 2014 Samsung Electronics. All rights reserved.
* @Author: Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
*
* 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.
*/
/**
* SECTION:element-dvbsrc
*
* dvbsrc can be used to capture media from DVB cards. Supported DTV
* broadcasting standards include DVB-T/C/S, ATSC ,ISDB-T and DTMB.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch-1.0 dvbsrc modulation="QAM 64" trans-mode=8k bandwidth=8 frequency=514000000 code-rate-lp=AUTO code-rate-hp=2/3 guard=4 hierarchy=0 ! mpegtsdemux name=demux ! queue max-size-buffers=0 max-size-time=0 ! mpeg2dec ! xvimagesink demux. ! queue max-size-buffers=0 max-size-time=0 ! mad ! alsasink
* ]| Captures a full transport stream from DVB card 0 that is a DVB-T card at tuned frequency 514000000 Hz with other parameters as seen in the pipeline and renders the first TV program on the transport stream.
* |[
* gst-launch-1.0 dvbsrc modulation="QAM 64" trans-mode=8k bandwidth=8 frequency=514000000 code-rate-lp=AUTO code-rate-hp=2/3 guard=4 hierarchy=0 pids=100:256:257 ! mpegtsdemux name=demux ! queue max-size-buffers=0 max-size-time=0 ! mpeg2dec ! xvimagesink demux. ! queue max-size-buffers=0 max-size-time=0 ! mad ! alsasink
* ]| Captures and renders a transport stream from DVB card 0 that is a DVB-T card for a program at tuned frequency 514000000 Hz with PMT PID 100 and elementary stream PIDs of 256, 257 with other parameters as seen in the pipeline.
* |[
* gst-launch-1.0 dvbsrc polarity="h" frequency=11302000 symbol-rate=27500 diseqc-source=0 pids=50:102:103 ! mpegtsdemux name=demux ! queue max-size-buffers=0 max-size-time=0 ! mpeg2dec ! xvimagesink demux. ! queue max-size-buffers=0 max-size-time=0 ! mad ! alsasink
* ]| Captures and renders a transport stream from DVB card 0 that is a DVB-S card for a program at tuned frequency 11302000 kHz, symbol rate of 27500 kBd (kilo bauds) with PMT PID of 50 and elementary stream PIDs of 102 and 103.
* |[
gst-launch-1.0 dvbsrc frequency=515142857 guard=16 trans-mode="8k" isdbt-layer-enabled=7 isdbt-partial-reception=1 isdbt-layera-fec="2/3" isdbt-layera-modulation="QPSK" isdbt-layera-segment-count=1 isdbt-layera-time-interleaving=4 isdbt-layerb-fec="3/4" isdbt-layerb-modulation="qam-64" isdbt-layerb-segment-count=12 isdbt-layerb-time-interleaving=2 isdbt-layerc-fec="1/2" isdbt-layerc-modulation="qam-64" isdbt-layerc-segment-count=0 isdbt-layerc-time-interleaving=0 delsys="isdb-t" ! tsdemux ! "video/x-h264" ! h264parse ! queue ! avdec_h264 ! videoconvert ! queue ! autovideosink
* ]| Captures and renders the video track of TV Paraíba HD (Globo affiliate) in Campina Grande, Brazil. This is an ISDB-T (Brazilian ISDB-Tb variant) broadcast.
* </refsect2>
*/
/*
* History of DVB_API_VERSION 5 minor changes
*
* API Addition/changes in reverse order (most recent first)
*
* Minor 10 (statistics properties)
* DTV_STAT_*
* FE_SCALE_*
*
* Minor 9
* DTV_LNA
* LNA_AUTO
*
* Minor 8
* FE_CAN_MULTISTREAM
* DTV_ISDBS_TS_ID_LEGACY (was DVB_ISDBS_TS_ID)
* DTV_DVBT2_PLP_ID_LEGACY (was DVB_DVBT2_PLP_ID)
* NO_STREAM_ID_FILTER
* INTERLEAVING_AUTO
*
* Minor 7 (DTMB Support)
* FEC_2_5
* QAM_4_NR
* TRANSMISSION_MODE_C1 / _C3780
* GUARD_INTERVAL_PN420 / _PN595 / _PN945
* INTERLEAVING_NONE / _240 / _720
* DTV_INTERLEAVING
* SYS_DTMB (Renamed from SYS_DMBTH but has safety #define)
*
* Minor 6 (ATSC-MH)
* DTV_ATSCMH_* (for those not defined in later versions)
*
* Somewhere in between 5 and 6:
* SYS_DVBC_ANNEX_A / _C (Safety #define for _AC => A)
*
* Minor 5 (Note : minimum version we support according to configure.ac)
* DTV_ENUM_DELSYS
*/
/* We know we have at least DVB_API_VERSION >= 5 (minor 5) */
#define HAVE_V5_MINOR(minor) ((DVB_API_VERSION > 5) || \
(DVB_API_VERSION_MINOR >= (minor)))
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstdvbsrc.h"
#include <gst/gst.h>
#include <gst/glib-compat-private.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/dvb/version.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
#include <gst/gst-i18n-plugin.h>
/* Before 5.6 we map A to AC */
#if !HAVE_V5_MINOR(6)
#define SYS_DVBC_ANNEX_A SYS_DVBC_ANNEX_AC
#endif
/* NO_STREAM_ID_FILTER introduced in minor 8 */
#ifndef NO_STREAM_ID_FILTER
#define NO_STREAM_ID_FILTER (~0U)
#endif
/* DTV_STREAM_ID introduced in minor 8 (redefine) */
#ifndef DTV_STREAM_ID
#define DTV_STREAM_ID DTV_ISDBS_TS_ID
#endif
GST_DEBUG_CATEGORY_STATIC (gstdvbsrc_debug);
#define GST_CAT_DEFAULT (gstdvbsrc_debug)
/**
* Can't be greater than DTV_IOCTL_MAX_MSGS but we are
* not using more than 25 for the largest use case (ISDB-T).
*
* Bump as needed.
*/
#define NUM_DTV_PROPS 25
/* Signals */
enum
{
SIGNAL_TUNING_START,
SIGNAL_TUNING_DONE,
SIGNAL_TUNING_FAIL,
SIGNAL_TUNE,
LAST_SIGNAL
};
/* Arguments */
enum
{
ARG_0,
ARG_DVBSRC_ADAPTER,
ARG_DVBSRC_FRONTEND,
ARG_DVBSRC_DISEQC_SRC,
ARG_DVBSRC_FREQUENCY,
ARG_DVBSRC_POLARITY,
ARG_DVBSRC_PIDS,
ARG_DVBSRC_SYM_RATE,
ARG_DVBSRC_BANDWIDTH,
ARG_DVBSRC_CODE_RATE_HP,
ARG_DVBSRC_CODE_RATE_LP,
ARG_DVBSRC_GUARD,
ARG_DVBSRC_MODULATION,
ARG_DVBSRC_TRANSMISSION_MODE,
ARG_DVBSRC_HIERARCHY_INF,
ARG_DVBSRC_TUNE,
ARG_DVBSRC_INVERSION,
ARG_DVBSRC_STATS_REPORTING_INTERVAL,
ARG_DVBSRC_TIMEOUT,
ARG_DVBSRC_TUNING_TIMEOUT,
ARG_DVBSRC_DVB_BUFFER_SIZE,
ARG_DVBSRC_DELSYS,
ARG_DVBSRC_PILOT,
ARG_DVBSRC_ROLLOFF,
ARG_DVBSRC_STREAM_ID,
ARG_DVBSRC_BANDWIDTH_HZ,
ARG_DVBSRC_ISDBT_LAYER_ENABLED,
ARG_DVBSRC_ISDBT_PARTIAL_RECEPTION,
ARG_DVBSRC_ISDBT_SOUND_BROADCASTING,
ARG_DVBSRC_ISDBT_SB_SUBCHANNEL_ID,
ARG_DVBSRC_ISDBT_SB_SEGMENT_IDX,
ARG_DVBSRC_ISDBT_SB_SEGMENT_COUNT,
ARG_DVBSRC_ISDBT_LAYERA_FEC,
ARG_DVBSRC_ISDBT_LAYERA_MODULATION,
ARG_DVBSRC_ISDBT_LAYERA_SEGMENT_COUNT,
ARG_DVBSRC_ISDBT_LAYERA_TIME_INTERLEAVING,
ARG_DVBSRC_ISDBT_LAYERB_FEC,
ARG_DVBSRC_ISDBT_LAYERB_MODULATION,
ARG_DVBSRC_ISDBT_LAYERB_SEGMENT_COUNT,
ARG_DVBSRC_ISDBT_LAYERB_TIME_INTERLEAVING,
ARG_DVBSRC_ISDBT_LAYERC_FEC,
ARG_DVBSRC_ISDBT_LAYERC_MODULATION,
ARG_DVBSRC_ISDBT_LAYERC_SEGMENT_COUNT,
ARG_DVBSRC_ISDBT_LAYERC_TIME_INTERLEAVING,
ARG_DVBSRC_LNB_SLOF,
ARG_DVBSRC_LNB_LOF1,
ARG_DVBSRC_LNB_LOF2,
ARG_DVBSRC_INTERLEAVING
};
#define DEFAULT_ADAPTER 0
#define DEFAULT_FRONTEND 0
#define DEFAULT_DISEQC_SRC -1 /* disabled */
#define DEFAULT_FREQUENCY 0
#define DEFAULT_POLARITY "H"
#define DEFAULT_PIDS "8192" /* Special value meaning 'all' PIDs */
#define DEFAULT_SYMBOL_RATE 0
#define DEFAULT_BANDWIDTH_HZ 8000000
#define DEFAULT_BANDWIDTH BANDWIDTH_8_MHZ
#define DEFAULT_CODE_RATE_HP FEC_AUTO
#define DEFAULT_CODE_RATE_LP FEC_1_2
#define DEFAULT_GUARD GUARD_INTERVAL_1_16
#define DEFAULT_MODULATION QAM_16
#define DEFAULT_TRANSMISSION_MODE TRANSMISSION_MODE_8K
#define DEFAULT_HIERARCHY HIERARCHY_1
#define DEFAULT_INVERSION INVERSION_ON
#define DEFAULT_STATS_REPORTING_INTERVAL 100
#define DEFAULT_TIMEOUT 1000000 /* 1 second */
#define DEFAULT_TUNING_TIMEOUT 10 * GST_SECOND /* 10 seconds */
#define DEFAULT_DVB_BUFFER_SIZE (10*188*1024) /* kernel default is 8192 */
#define DEFAULT_BUFFER_SIZE 8192 /* not a property */
#define DEFAULT_DELSYS SYS_UNDEFINED
#define DEFAULT_PILOT PILOT_AUTO
#define DEFAULT_ROLLOFF ROLLOFF_AUTO
#define DEFAULT_STREAM_ID NO_STREAM_ID_FILTER
#define DEFAULT_ISDBT_LAYER_ENABLED 7
#define DEFAULT_ISDBT_PARTIAL_RECEPTION 1
#define DEFAULT_ISDBT_SOUND_BROADCASTING 0
#define DEFAULT_ISDBT_SB_SUBCHANNEL_ID -1
#define DEFAULT_ISDBT_SB_SEGMENT_IDX 0
#define DEFAULT_ISDBT_SB_SEGMENT_COUNT 1
#define DEFAULT_ISDBT_LAYERA_FEC FEC_AUTO
#define DEFAULT_ISDBT_LAYERA_MODULATION QAM_AUTO
#define DEFAULT_ISDBT_LAYERA_SEGMENT_COUNT -1
#define DEFAULT_ISDBT_LAYERA_TIME_INTERLEAVING -1
#define DEFAULT_ISDBT_LAYERB_FEC FEC_AUTO
#define DEFAULT_ISDBT_LAYERB_MODULATION QAM_AUTO
#define DEFAULT_ISDBT_LAYERB_SEGMENT_COUNT -1
#define DEFAULT_ISDBT_LAYERB_TIME_INTERLEAVING -1
#define DEFAULT_ISDBT_LAYERC_FEC FEC_AUTO
#define DEFAULT_ISDBT_LAYERC_MODULATION QAM_AUTO
#define DEFAULT_ISDBT_LAYERC_SEGMENT_COUNT -1
#define DEFAULT_ISDBT_LAYERC_TIME_INTERLEAVING -1
#define DEFAULT_LNB_SLOF (11700*1000UL)
#define DEFAULT_LNB_LOF1 (9750*1000UL)
#define DEFAULT_LNB_LOF2 (10600*1000UL)
#if HAVE_V5_MINOR(7)
#define DEFAULT_INTERLEAVING INTERLEAVING_AUTO
#else
#define DEFAULT_INTERLEAVING 0
#endif
static void gst_dvbsrc_output_frontend_stats (GstDvbSrc * src);
#define GST_TYPE_DVBSRC_CODE_RATE (gst_dvbsrc_code_rate_get_type ())
static GType
gst_dvbsrc_code_rate_get_type (void)
{
static GType dvbsrc_code_rate_type = 0;
static const GEnumValue code_rate_types[] = {
{FEC_NONE, "NONE", "none"},
{FEC_1_2, "1/2", "1/2"},
{FEC_2_3, "2/3", "2/3"},
{FEC_3_4, "3/4", "3/4"},
{FEC_4_5, "4/5", "4/5"},
{FEC_5_6, "5/6", "5/6"},
{FEC_6_7, "6/7", "6/7"},
{FEC_7_8, "7/8", "7/8"},
{FEC_8_9, "8/9", "8/9"},
{FEC_AUTO, "AUTO", "auto"},
{FEC_3_5, "3/5", "3/5"},
{FEC_9_10, "9/10", "9/10"},
{FEC_2_5, "2/5", "2/5"},
{0, NULL, NULL},
};
if (!dvbsrc_code_rate_type) {
dvbsrc_code_rate_type =
g_enum_register_static ("GstDvbSrcCode_Rate", code_rate_types);
}
return dvbsrc_code_rate_type;
}
#define GST_TYPE_DVBSRC_MODULATION (gst_dvbsrc_modulation_get_type ())
static GType
gst_dvbsrc_modulation_get_type (void)
{
static GType dvbsrc_modulation_type = 0;
static const GEnumValue modulation_types[] = {
{QPSK, "QPSK", "qpsk"},
{QAM_16, "QAM 16", "qam-16"},
{QAM_32, "QAM 32", "qam-32"},
{QAM_64, "QAM 64", "qam-64"},
{QAM_128, "QAM 128", "qam-128"},
{QAM_256, "QAM 256", "qam-256"},
{QAM_AUTO, "AUTO", "auto"},
{VSB_8, "8VSB", "8vsb"},
{VSB_16, "16VSB", "16vsb"},
{PSK_8, "8PSK", "8psk"},
{APSK_16, "16APSK", "16apsk"},
{APSK_32, "32APSK", "32apsk"},
{DQPSK, "DQPSK", "dqpsk"},
{QAM_4_NR, "QAM 4 NR", "qam-4-nr"},
{0, NULL, NULL},
};
if (!dvbsrc_modulation_type) {
dvbsrc_modulation_type =
g_enum_register_static ("GstDvbSrcModulation", modulation_types);
}
return dvbsrc_modulation_type;
}
#define GST_TYPE_DVBSRC_TRANSMISSION_MODE (gst_dvbsrc_transmission_mode_get_type ())
static GType
gst_dvbsrc_transmission_mode_get_type (void)
{
static GType dvbsrc_transmission_mode_type = 0;
static const GEnumValue transmission_mode_types[] = {
{TRANSMISSION_MODE_2K, "2K", "2k"},
{TRANSMISSION_MODE_8K, "8K", "8k"},
{TRANSMISSION_MODE_AUTO, "AUTO", "auto"},
{TRANSMISSION_MODE_4K, "4K", "4k"},
{TRANSMISSION_MODE_1K, "1K", "1k"},
{TRANSMISSION_MODE_16K, "16K", "16k"},
{TRANSMISSION_MODE_32K, "32K", "32k"},
#if HAVE_V5_MINOR(7)
{TRANSMISSION_MODE_C1, "C1", "c1"},
{TRANSMISSION_MODE_C3780, "C3780", "c3780"},
#endif
{0, NULL, NULL},
};
if (!dvbsrc_transmission_mode_type) {
dvbsrc_transmission_mode_type =
g_enum_register_static ("GstDvbSrcTransmission_Mode",
transmission_mode_types);
}
return dvbsrc_transmission_mode_type;
}
#define GST_TYPE_DVBSRC_BANDWIDTH (gst_dvbsrc_bandwidth_get_type ())
static GType
gst_dvbsrc_bandwidth_get_type (void)
{
static GType dvbsrc_bandwidth_type = 0;
static const GEnumValue bandwidth_types[] = {
{BANDWIDTH_8_MHZ, "8", "8"},
{BANDWIDTH_7_MHZ, "7", "7"},
{BANDWIDTH_6_MHZ, "6", "6"},
{BANDWIDTH_AUTO, "AUTO", "AUTO"},
{BANDWIDTH_5_MHZ, "5", "5"},
{BANDWIDTH_10_MHZ, "10", "10"},
{BANDWIDTH_1_712_MHZ, "1.712", "1.712"},
{0, NULL, NULL},
};
if (!dvbsrc_bandwidth_type) {
dvbsrc_bandwidth_type =
g_enum_register_static ("GstDvbSrcBandwidth", bandwidth_types);
}
return dvbsrc_bandwidth_type;
}
#define GST_TYPE_DVBSRC_GUARD (gst_dvbsrc_guard_get_type ())
static GType
gst_dvbsrc_guard_get_type (void)
{
static GType dvbsrc_guard_type = 0;
static const GEnumValue guard_types[] = {
{GUARD_INTERVAL_1_32, "32", "32"},
{GUARD_INTERVAL_1_16, "16", "16"},
{GUARD_INTERVAL_1_8, "8", "8"},
{GUARD_INTERVAL_1_4, "4", "4"},
{GUARD_INTERVAL_AUTO, "AUTO", "auto"},
{GUARD_INTERVAL_1_128, "128", "128"},
{GUARD_INTERVAL_19_128, "19/128", "19/128"},
{GUARD_INTERVAL_19_256, "19/256", "19/256"},
#if HAVE_V5_MINOR(7)
{GUARD_INTERVAL_PN420, "PN420", "pn420"},
{GUARD_INTERVAL_PN595, "PN595", "pn595"},
{GUARD_INTERVAL_PN945, "PN945", "pn945"},
#endif
{0, NULL, NULL},
};
if (!dvbsrc_guard_type) {
dvbsrc_guard_type = g_enum_register_static ("GstDvbSrcGuard", guard_types);
}
return dvbsrc_guard_type;
}
#define GST_TYPE_DVBSRC_HIERARCHY (gst_dvbsrc_hierarchy_get_type ())
static GType
gst_dvbsrc_hierarchy_get_type (void)
{
static GType dvbsrc_hierarchy_type = 0;
static const GEnumValue hierarchy_types[] = {
{HIERARCHY_NONE, "NONE", "none"},
{HIERARCHY_1, "1", "1"},
{HIERARCHY_2, "2", "2"},
{HIERARCHY_4, "4", "4"},
{HIERARCHY_AUTO, "AUTO", "auto"},
{0, NULL, NULL},
};
if (!dvbsrc_hierarchy_type) {
dvbsrc_hierarchy_type =
g_enum_register_static ("GstDvbSrcHierarchy", hierarchy_types);
}
return dvbsrc_hierarchy_type;
}
#define GST_TYPE_DVBSRC_INVERSION (gst_dvbsrc_inversion_get_type ())
static GType
gst_dvbsrc_inversion_get_type (void)
{
static GType dvbsrc_inversion_type = 0;
static const GEnumValue inversion_types[] = {
{INVERSION_OFF, "OFF", "off"},
{INVERSION_ON, "ON", "on"},
{INVERSION_AUTO, "AUTO", "auto"},
{0, NULL, NULL},
};
if (!dvbsrc_inversion_type) {
dvbsrc_inversion_type =
g_enum_register_static ("GstDvbSrcInversion", inversion_types);
}
return dvbsrc_inversion_type;
}
#define GST_TYPE_DVBSRC_DELSYS (gst_dvbsrc_delsys_get_type ())
static GType
gst_dvbsrc_delsys_get_type (void)
{
static GType dvbsrc_delsys_type = 0;
static const GEnumValue delsys_types[] = {
{SYS_UNDEFINED, "UNDEFINED", "undefined"},
{SYS_DVBC_ANNEX_A, "DVB-C-A", "dvb-c-a"},
{SYS_DVBC_ANNEX_B, "DVB-C-B", "dvb-c-b"},
{SYS_DVBT, "DVB-T", "dvb-t"},
{SYS_DSS, "DSS", "dss"},
{SYS_DVBS, "DVB-S", "dvb-s"},
{SYS_DVBS2, "DVB-S2", "dvb-s2"},
{SYS_DVBH, "DVB-H", "dvb-h"},
{SYS_ISDBT, "ISDB-T", "isdb-t"},
{SYS_ISDBS, "ISDB-S", "isdb-s"},
{SYS_ISDBC, "ISDB-C", "isdb-c"},
{SYS_ATSC, "ATSC", "atsc"},
{SYS_ATSCMH, "ATSC-MH", "atsc-mh"},
#if HAVE_V5_MINOR(7)
{SYS_DTMB, "DTMB", "dtmb"},
#endif
{SYS_CMMB, "CMMB", "cmmb"},
{SYS_DAB, "DAB", "dab"},
{SYS_DVBT2, "DVB-T2", "dvb-t2"},
{SYS_TURBO, "TURBO", "turbo"},
#if HAVE_V5_MINOR(6)
{SYS_DVBC_ANNEX_C, "DVB-C-C", "dvb-c-c"},
#endif
{0, NULL, NULL},
};
if (!dvbsrc_delsys_type) {
dvbsrc_delsys_type =
g_enum_register_static ("GstDvbSrcDelsys", delsys_types);
}
return dvbsrc_delsys_type;
}
#define GST_TYPE_DVBSRC_PILOT (gst_dvbsrc_pilot_get_type ())
static GType
gst_dvbsrc_pilot_get_type (void)
{
static GType dvbsrc_pilot_type = 0;
static const GEnumValue pilot_types[] = {
{PILOT_ON, "ON", "on"},
{PILOT_OFF, "OFF", "off"},
{PILOT_AUTO, "AUTO", "auto"},
{0, NULL, NULL},
};
if (!dvbsrc_pilot_type) {
dvbsrc_pilot_type = g_enum_register_static ("GstDvbSrcPilot", pilot_types);
}
return dvbsrc_pilot_type;
}
#define GST_TYPE_DVBSRC_ROLLOFF (gst_dvbsrc_rolloff_get_type ())
static GType
gst_dvbsrc_rolloff_get_type (void)
{
static GType dvbsrc_rolloff_type = 0;
static const GEnumValue rolloff_types[] = {
{ROLLOFF_35, "35", "35"},
{ROLLOFF_20, "20", "20"},
{ROLLOFF_25, "25", "25"},
{ROLLOFF_AUTO, "auto", "auto"},
{0, NULL, NULL},
};
if (!dvbsrc_rolloff_type) {
dvbsrc_rolloff_type =
g_enum_register_static ("GstDvbSrcRolloff", rolloff_types);
}
return dvbsrc_rolloff_type;
}
#define GST_TYPE_INTERLEAVING (gst_dvbsrc_interleaving_get_type ())
static GType
gst_dvbsrc_interleaving_get_type (void)
{
static GType dvbsrc_interleaving_type = 0;
static const GEnumValue interleaving_types[] = {
#if HAVE_V5_MINOR(7)
{INTERLEAVING_NONE, "NONE", "none"},
{INTERLEAVING_AUTO, "AUTO", "auto"},
{INTERLEAVING_240, "240", "240"},
{INTERLEAVING_720, "720", "720"},
#endif
{0, NULL, NULL},
};
if (!dvbsrc_interleaving_type) {
dvbsrc_interleaving_type =
g_enum_register_static ("GstDvbSrcInterleaving", interleaving_types);
}
return dvbsrc_interleaving_type;
}
static void gst_dvbsrc_finalize (GObject * object);
static void gst_dvbsrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_dvbsrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstFlowReturn gst_dvbsrc_create (GstPushSrc * element,
GstBuffer ** buffer);
static gboolean gst_dvbsrc_start (GstBaseSrc * bsrc);
static gboolean gst_dvbsrc_stop (GstBaseSrc * bsrc);
static GstStateChangeReturn gst_dvbsrc_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_dvbsrc_unlock (GstBaseSrc * bsrc);
static gboolean gst_dvbsrc_unlock_stop (GstBaseSrc * bsrc);
static gboolean gst_dvbsrc_is_seekable (GstBaseSrc * bsrc);
static gboolean gst_dvbsrc_get_size (GstBaseSrc * src, guint64 * size);
static void gst_dvbsrc_do_tune (GstDvbSrc * src);
static gboolean gst_dvbsrc_tune (GstDvbSrc * object);
static gboolean gst_dvbsrc_set_fe_params (GstDvbSrc * object,
struct dtv_properties *props);
static gboolean gst_dvbsrc_tune_fe (GstDvbSrc * object);
static void gst_dvbsrc_set_pes_filters (GstDvbSrc * object);
static void gst_dvbsrc_unset_pes_filters (GstDvbSrc * object);
static gboolean gst_dvbsrc_is_valid_modulation (guint delsys, guint mod);
/**
* This loop should be safe enough considering:
*
* 1.- EINTR suggest the next ioctl might succeed
* 2.- It's highly unlikely you will end up spining
* before your entire system goes nuts due to
* the massive number of interrupts.
*
* We don't check for EAGAIN here cause we are opening
* the frontend in blocking mode.
*/
#define LOOP_WHILE_EINTR(v,func) do { (v) = (func); } \
while ((v) == -1 && errno == EINTR);
static GstStaticPadTemplate ts_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
("video/mpegts, "
"mpegversion = (int) 2," "systemstream = (boolean) TRUE"));
/*
******************************
* *
* GObject Related *
* *
* *
******************************
*/
#define gst_dvbsrc_parent_class parent_class
G_DEFINE_TYPE (GstDvbSrc, gst_dvbsrc, GST_TYPE_PUSH_SRC);
static guint gst_dvbsrc_signals[LAST_SIGNAL] = { 0 };
/* initialize the plugin's class */
static void
gst_dvbsrc_class_init (GstDvbSrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpushsrc_class;
GstDvbSrcClass *gstdvbsrc_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpushsrc_class = (GstPushSrcClass *) klass;
gstdvbsrc_class = (GstDvbSrcClass *) klass;
gobject_class->set_property = gst_dvbsrc_set_property;
gobject_class->get_property = gst_dvbsrc_get_property;
gobject_class->finalize = gst_dvbsrc_finalize;
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_dvbsrc_change_state);
gst_element_class_add_static_pad_template (gstelement_class, &ts_src_factory);
gst_element_class_set_static_metadata (gstelement_class, "DVB Source",
"Source/Video",
"Digital Video Broadcast Source",
"P2P-VCR, C-Lab, University of Paderborn, "
"Zaheer Abbas Merali <zaheerabbas at merali dot org>\n"
"Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>");
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_dvbsrc_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_dvbsrc_stop);
gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_dvbsrc_unlock);
gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_dvbsrc_unlock_stop);
gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_dvbsrc_is_seekable);
gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_dvbsrc_get_size);
gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_dvbsrc_create);
gstdvbsrc_class->do_tune = GST_DEBUG_FUNCPTR (gst_dvbsrc_do_tune);
g_object_class_install_property (gobject_class, ARG_DVBSRC_ADAPTER,
g_param_spec_int ("adapter", "The adapter device number",
"The DVB adapter device number (eg. 0 for adapter0)",
0, 16, DEFAULT_ADAPTER, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_FRONTEND,
g_param_spec_int ("frontend", "The frontend device number",
"The frontend device number (eg. 0 for frontend0)",
0, 16, DEFAULT_FRONTEND, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_FREQUENCY,
g_param_spec_uint ("frequency", "Center frequency",
"Center frequency to tune into. Measured in kHz for the satellite "
"distribution standars and Hz for all the rest",
0, G_MAXUINT, DEFAULT_FREQUENCY,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_POLARITY,
g_param_spec_string ("polarity", "polarity",
"(DVB-S/S2) Polarity [vhHV] (eg. V for Vertical)",
DEFAULT_POLARITY,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, ARG_DVBSRC_PIDS,
g_param_spec_string ("pids", "pids",
"Colon seperated list of pids (eg. 110:120)",
DEFAULT_PIDS, GST_PARAM_MUTABLE_PLAYING | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_SYM_RATE,
g_param_spec_uint ("symbol-rate",
"symbol rate",
"(DVB-S/S2, DVB-C) Symbol rate in kBd (kilo bauds)",
0, G_MAXUINT, DEFAULT_SYMBOL_RATE,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_TUNE,
g_param_spec_pointer ("tune",
"tune", "Atomically tune to channel. (For Apps)", G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_DISEQC_SRC,
g_param_spec_int ("diseqc-source",
"diseqc source",
"(DVB-S/S2) Selected DiSEqC source. Only needed if you have a "
"DiSEqC switch. Otherwise leave at -1 (disabled)", -1, 7,
DEFAULT_DISEQC_SRC, GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
/* DVB-T, additional properties */
g_object_class_install_property (gobject_class, ARG_DVBSRC_BANDWIDTH_HZ,
g_param_spec_uint ("bandwidth-hz", "bandwidth-hz",
"(DVB-T) Bandwidth in Hz", 0, G_MAXUINT, DEFAULT_BANDWIDTH_HZ,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
#ifndef GST_REMOVE_DEPRECATED
g_object_class_install_property (gobject_class, ARG_DVBSRC_BANDWIDTH,
g_param_spec_enum ("bandwidth", "bandwidth",
"(DVB-T) Bandwidth. Deprecated", GST_TYPE_DVBSRC_BANDWIDTH,
DEFAULT_BANDWIDTH,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE | G_PARAM_DEPRECATED));
#endif
/* FIXME: DVB-C, DVB-S, DVB-S2 named it as innerFEC */
g_object_class_install_property (gobject_class, ARG_DVBSRC_CODE_RATE_HP,
g_param_spec_enum ("code-rate-hp",
"code-rate-hp",
"(DVB-T, DVB-S/S2 and DVB-C) High priority code rate",
GST_TYPE_DVBSRC_CODE_RATE, DEFAULT_CODE_RATE_HP,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_CODE_RATE_LP,
g_param_spec_enum ("code-rate-lp",
"code-rate-lp",
"(DVB-T) Low priority code rate",
GST_TYPE_DVBSRC_CODE_RATE, DEFAULT_CODE_RATE_LP,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
/* FIXME: should the property be called 'guard-interval' then? */
g_object_class_install_property (gobject_class, ARG_DVBSRC_GUARD,
g_param_spec_enum ("guard",
"guard",
"(DVB-T) Guard Interval",
GST_TYPE_DVBSRC_GUARD, DEFAULT_GUARD,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_MODULATION,
g_param_spec_enum ("modulation", "modulation",
"(DVB-T/T2/C/S2, TURBO and ATSC) Modulation type",
GST_TYPE_DVBSRC_MODULATION, DEFAULT_MODULATION,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
/* FIXME: property should be named 'transmission-mode' */
g_object_class_install_property (gobject_class,
ARG_DVBSRC_TRANSMISSION_MODE,
g_param_spec_enum ("trans-mode", "trans-mode",
"(DVB-T) Transmission mode",
GST_TYPE_DVBSRC_TRANSMISSION_MODE, DEFAULT_TRANSMISSION_MODE,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_HIERARCHY_INF,
g_param_spec_enum ("hierarchy", "hierarchy",
"(DVB-T) Hierarchy information",
GST_TYPE_DVBSRC_HIERARCHY, DEFAULT_HIERARCHY,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_INVERSION,
g_param_spec_enum ("inversion", "inversion",
"(DVB-T and DVB-C) Inversion information",
GST_TYPE_DVBSRC_INVERSION, DEFAULT_INVERSION,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_STATS_REPORTING_INTERVAL,
g_param_spec_uint ("stats-reporting-interval",
"stats-reporting-interval",
"The number of reads before reporting frontend stats",
0, G_MAXUINT, DEFAULT_STATS_REPORTING_INTERVAL,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_TIMEOUT,
g_param_spec_uint64 ("timeout", "Timeout",
"Post a message after timeout microseconds (0 = disabled)",
0, G_MAXUINT64, DEFAULT_TIMEOUT, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_TUNING_TIMEOUT,
g_param_spec_uint64 ("tuning-timeout", "Tuning Timeout",
"Milliseconds to wait before giving up tuning/locking on a signal",
0, G_MAXUINT64, DEFAULT_TUNING_TIMEOUT,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_DVB_BUFFER_SIZE,
g_param_spec_uint ("dvb-buffer-size",
"dvb-buffer-size",
"The kernel buffer size used by the DVB api",
0, G_MAXUINT, DEFAULT_DVB_BUFFER_SIZE, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_DELSYS,
g_param_spec_enum ("delsys", "delsys", "Delivery System",
GST_TYPE_DVBSRC_DELSYS, DEFAULT_DELSYS, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_PILOT,
g_param_spec_enum ("pilot", "pilot", "Pilot (DVB-S2)",
GST_TYPE_DVBSRC_PILOT, DEFAULT_PILOT,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_ROLLOFF,
g_param_spec_enum ("rolloff", "rolloff", "Rolloff (DVB-S2)",
GST_TYPE_DVBSRC_ROLLOFF, DEFAULT_ROLLOFF,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_STREAM_ID,
g_param_spec_int ("stream-id", "stream-id",
"(DVB-T2 and DVB-S2 max 255, ISDB max 65535) Stream ID "
"(-1 = disabled)", -1, 65535, DEFAULT_STREAM_ID,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
/* Additional ISDB-T properties */
/* Valid values are 0x1 0x2 0x4 |-ables */
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYER_ENABLED,
g_param_spec_uint ("isdbt-layer-enabled",
"ISB-T layer enabled",
"(ISDB-T) Layer Enabled (7 = All layers)", 1, 7,
DEFAULT_ISDBT_LAYER_ENABLED,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_PARTIAL_RECEPTION,
g_param_spec_int ("isdbt-partial-reception",
"ISB-T partial reception",
"(ISDB-T) Partial Reception (-1 = AUTO)", -1, 1,
DEFAULT_ISDBT_PARTIAL_RECEPTION,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_SOUND_BROADCASTING,
g_param_spec_int ("isdbt-sound-broadcasting",
"ISB-T sound broadcasting",
"(ISDB-T) Sound Broadcasting", 0, 1,
DEFAULT_ISDBT_SOUND_BROADCASTING,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_SB_SUBCHANNEL_ID,
g_param_spec_int ("isdbt-sb-subchannel-id",
"ISB-T SB subchannel ID",
"(ISDB-T) SB Subchannel ID (-1 = AUTO)", -1, 41,
DEFAULT_ISDBT_SB_SEGMENT_IDX,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_SB_SEGMENT_IDX,
g_param_spec_int ("isdbt-sb-segment-idx",
"ISB-T SB segment IDX",
"(ISDB-T) SB segment IDX", 0, 12,
DEFAULT_ISDBT_SB_SEGMENT_IDX,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_SB_SEGMENT_COUNT,
g_param_spec_uint ("isdbt-sb-segment-count",
"ISB-T SB segment count",
"(ISDB-T) SB segment count", 1, 13,
DEFAULT_ISDBT_SB_SEGMENT_COUNT,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_ISDBT_LAYERA_FEC,
g_param_spec_enum ("isdbt-layera-fec",
"ISDB-T layer A FEC", "(ISDB-T) layer A Forward Error Correction",
GST_TYPE_DVBSRC_CODE_RATE, DEFAULT_ISDBT_LAYERA_FEC,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_ISDBT_LAYERB_FEC,
g_param_spec_enum ("isdbt-layerb-fec",
"ISDB-T layer B FEC", "(ISDB-T) layer B Forward Error Correction",
GST_TYPE_DVBSRC_CODE_RATE, DEFAULT_ISDBT_LAYERB_FEC,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_ISDBT_LAYERC_FEC,
g_param_spec_enum ("isdbt-layerc-fec",
"ISDB-T layer A FEC", "(ISDB-T) layer C Forward Error Correction",
GST_TYPE_DVBSRC_CODE_RATE, DEFAULT_ISDBT_LAYERC_FEC,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERA_MODULATION,
g_param_spec_enum ("isdbt-layera-modulation", "ISDBT layer A modulation",
"(ISDB-T) Layer A modulation type",
GST_TYPE_DVBSRC_MODULATION, DEFAULT_ISDBT_LAYERA_MODULATION,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERB_MODULATION,
g_param_spec_enum ("isdbt-layerb-modulation", "ISDBT layer B modulation",
"(ISDB-T) Layer B modulation type",
GST_TYPE_DVBSRC_MODULATION, DEFAULT_ISDBT_LAYERB_MODULATION,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERC_MODULATION,
g_param_spec_enum ("isdbt-layerc-modulation", "ISDBT layer C modulation",
"(ISDB-T) Layer C modulation type",
GST_TYPE_DVBSRC_MODULATION, DEFAULT_ISDBT_LAYERC_MODULATION,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERA_SEGMENT_COUNT,
g_param_spec_int ("isdbt-layera-segment-count",
"ISB-T layer A segment count",
"(ISDB-T) Layer A segment count (-1 = AUTO)", -1, 13,
DEFAULT_ISDBT_LAYERA_SEGMENT_COUNT,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERB_SEGMENT_COUNT,
g_param_spec_int ("isdbt-layerb-segment-count",
"ISB-T layer B segment count",
"(ISDB-T) Layer B segment count (-1 = AUTO)", -1, 13,
DEFAULT_ISDBT_LAYERB_SEGMENT_COUNT,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERC_SEGMENT_COUNT,
g_param_spec_int ("isdbt-layerc-segment-count",
"ISB-T layer C segment count",
"(ISDB-T) Layer C segment count (-1 = AUTO)", -1, 13,
DEFAULT_ISDBT_LAYERC_SEGMENT_COUNT,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERA_TIME_INTERLEAVING,
g_param_spec_int ("isdbt-layera-time-interleaving",
"ISB-T layer A time interleaving ",
"(ISDB-T) Layer A time interleaving (-1 = AUTO)", -1, 8,
DEFAULT_ISDBT_LAYERA_TIME_INTERLEAVING,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERB_TIME_INTERLEAVING,
g_param_spec_int ("isdbt-layerb-time-interleaving",
"ISB-T layer B time interleaving ",
"(ISDB-T) Layer B time interleaving (-1 = AUTO)", -1, 8,
DEFAULT_ISDBT_LAYERB_TIME_INTERLEAVING,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
ARG_DVBSRC_ISDBT_LAYERC_TIME_INTERLEAVING,
g_param_spec_int ("isdbt-layerc-time-interleaving",
"ISB-T layer C time interleaving ",
"(ISDB-T) Layer C time interleaving (-1 = AUTO)", -1, 8,
DEFAULT_ISDBT_LAYERC_TIME_INTERLEAVING,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
/* LNB properties (Satellite distribution standards) */
g_object_class_install_property (gobject_class, ARG_DVBSRC_LNB_SLOF,
g_param_spec_uint ("lnb-slof", "Tuning Timeout",
"LNB's Upper bound for low band reception (kHz)",
0, G_MAXUINT, DEFAULT_LNB_SLOF,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_LNB_LOF1,
g_param_spec_uint ("lnb-lof1", "Low band local oscillator frequency",
"LNB's Local oscillator frequency used for low band reception (kHz)",
0, G_MAXUINT, DEFAULT_LNB_LOF1,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DVBSRC_LNB_LOF2,
g_param_spec_uint ("lnb-lof2", "High band local oscillator frequency",
"LNB's Local oscillator frequency used for high band reception (kHz)",
0, G_MAXUINT, DEFAULT_LNB_LOF2,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
/* Additional DTMB properties */
g_object_class_install_property (gobject_class,
ARG_DVBSRC_INTERLEAVING,
g_param_spec_enum ("interleaving", "DTMB Interleaving",
"(DTMB) Interleaving type",
GST_TYPE_INTERLEAVING, DEFAULT_INTERLEAVING,
GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE));
/**
* GstDvbSrc::tuning-start:
* @gstdvbsrc: the element on which the signal is emitted
*
* Signal emited when the element first attempts to tune the
* frontend tunner to a given frequency.
*/
gst_dvbsrc_signals[SIGNAL_TUNING_START] =
g_signal_new ("tuning-start", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
/**
* GstDvbSrc::tuning-done:
* @gstdvbsrc: the element on which the signal is emitted
*
* Signal emited when the tunner has successfully got a lock on a signal.
*/
gst_dvbsrc_signals[SIGNAL_TUNING_DONE] =
g_signal_new ("tuning-done", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
/**
* GstDvbSrc::tuning-fail:
* @gstdvbsrc: the element on which the signal is emitted
*
* Signal emited when the tunner failed to get a lock on the
* signal.
*/
gst_dvbsrc_signals[SIGNAL_TUNING_FAIL] =
g_signal_new ("tuning-fail", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
/**
* GstDvbSrc::tune:
* @gstdvbsrc: the element on which the signal is emitted
*
* Signal emited from the application to the element, instructing it
* to tune.
*/
gst_dvbsrc_signals[SIGNAL_TUNING_FAIL] =
g_signal_new ("tune", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstDvbSrcClass, do_tune),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}
/* initialize the new element
* instantiate pads and add them to element
* set functions
* initialize structure
*/
static void
gst_dvbsrc_init (GstDvbSrc * object)
{
int i = 0;
GST_INFO_OBJECT (object, "gst_dvbsrc_init");
GST_DEBUG_OBJECT (object, "Kernel DVB API version %d.%d", DVB_API_VERSION,
DVB_API_VERSION_MINOR);
/* We are a live source */
gst_base_src_set_live (GST_BASE_SRC (object), TRUE);
/* And we wanted timestamped output */
gst_base_src_set_do_timestamp (GST_BASE_SRC (object), TRUE);
gst_base_src_set_format (GST_BASE_SRC (object), GST_FORMAT_TIME);
object->fd_frontend = -1;
object->fd_dvr = -1;
for (i = 0; i < MAX_FILTERS; i++) {
object->pids[i] = G_MAXUINT16;
object->fd_filters[i] = -1;
}
/* PID 8192 on DVB gets the whole transport stream */
object->pids[0] = 8192;
object->dvb_buffer_size = DEFAULT_DVB_BUFFER_SIZE;
object->adapter_number = DEFAULT_ADAPTER;
object->frontend_number = DEFAULT_FRONTEND;
object->diseqc_src = DEFAULT_DISEQC_SRC;
object->send_diseqc = (DEFAULT_DISEQC_SRC != -1);
object->tone = SEC_TONE_OFF;
/* object->pol = DVB_POL_H; *//* set via G_PARAM_CONSTRUCT */
object->sym_rate = DEFAULT_SYMBOL_RATE;
object->bandwidth = DEFAULT_BANDWIDTH;
object->code_rate_hp = DEFAULT_CODE_RATE_HP;
object->code_rate_lp = DEFAULT_CODE_RATE_LP;
object->guard_interval = DEFAULT_GUARD;
object->modulation = DEFAULT_MODULATION;
object->transmission_mode = DEFAULT_TRANSMISSION_MODE;
object->hierarchy_information = DEFAULT_HIERARCHY;
object->inversion = DEFAULT_INVERSION;
object->stats_interval = DEFAULT_STATS_REPORTING_INTERVAL;
object->delsys = DEFAULT_DELSYS;
object->pilot = DEFAULT_PILOT;
object->rolloff = DEFAULT_ROLLOFF;
object->stream_id = DEFAULT_STREAM_ID;
object->isdbt_layer_enabled = DEFAULT_ISDBT_LAYER_ENABLED;
object->isdbt_partial_reception = DEFAULT_ISDBT_PARTIAL_RECEPTION;
object->isdbt_sound_broadcasting = DEFAULT_ISDBT_SOUND_BROADCASTING;
object->isdbt_sb_subchannel_id = DEFAULT_ISDBT_SB_SUBCHANNEL_ID;
object->isdbt_sb_segment_idx = DEFAULT_ISDBT_SB_SEGMENT_IDX;
object->isdbt_sb_segment_count = DEFAULT_ISDBT_SB_SEGMENT_COUNT;
object->isdbt_layera_fec = DEFAULT_ISDBT_LAYERA_FEC;
object->isdbt_layera_modulation = DEFAULT_ISDBT_LAYERA_MODULATION;
object->isdbt_layera_segment_count = DEFAULT_ISDBT_LAYERA_SEGMENT_COUNT;
object->isdbt_layera_time_interleaving =
DEFAULT_ISDBT_LAYERA_TIME_INTERLEAVING;
object->isdbt_layerb_fec = DEFAULT_ISDBT_LAYERB_FEC;
object->isdbt_layerb_modulation = DEFAULT_ISDBT_LAYERB_MODULATION;
object->isdbt_layerb_segment_count = DEFAULT_ISDBT_LAYERB_SEGMENT_COUNT;
object->isdbt_layerb_time_interleaving =
DEFAULT_ISDBT_LAYERB_TIME_INTERLEAVING;
object->isdbt_layerc_fec = DEFAULT_ISDBT_LAYERC_FEC;
object->isdbt_layerc_modulation = DEFAULT_ISDBT_LAYERC_MODULATION;
object->isdbt_layerc_segment_count = DEFAULT_ISDBT_LAYERC_SEGMENT_COUNT;
object->isdbt_layerc_time_interleaving =
DEFAULT_ISDBT_LAYERC_TIME_INTERLEAVING;
object->lnb_slof = DEFAULT_LNB_SLOF;
object->lnb_lof1 = DEFAULT_LNB_LOF1;
object->lnb_lof2 = DEFAULT_LNB_LOF2;
object->interleaving = DEFAULT_INTERLEAVING;
g_mutex_init (&object->tune_mutex);
object->timeout = DEFAULT_TIMEOUT;
object->tuning_timeout = DEFAULT_TUNING_TIMEOUT;
}
static void
gst_dvbsrc_set_pids (GstDvbSrc * dvbsrc, const gchar * pid_string)
{
if (!strcmp (pid_string, "8192")) {
/* get the whole ts */
int pid_count = 1;
dvbsrc->pids[0] = 8192;
while (pid_count < MAX_FILTERS) {
dvbsrc->pids[pid_count++] = G_MAXUINT16;
}
} else {
int pid = 0;
int pid_count;
gchar **pids;
char **tmp;
tmp = pids = g_strsplit (pid_string, ":", MAX_FILTERS);
/* always add the PAT and CAT pids */
dvbsrc->pids[0] = 0;
dvbsrc->pids[1] = 1;
pid_count = 2;
while (*pids != NULL && pid_count < MAX_FILTERS) {
pid = strtol (*pids, NULL, 0);
if (pid > 1 && pid <= 8192) {
GST_INFO_OBJECT (dvbsrc, "\tParsed Pid: %d", pid);
dvbsrc->pids[pid_count] = pid;
pid_count++;
}
pids++;
}
while (pid_count < MAX_FILTERS) {
dvbsrc->pids[pid_count++] = G_MAXUINT16;
}
g_strfreev (tmp);
}
/* if we are in playing or paused, then set filters now */
GST_INFO_OBJECT (dvbsrc, "checking if playing for setting pes filters");
if (GST_ELEMENT (dvbsrc)->current_state == GST_STATE_PLAYING ||
GST_ELEMENT (dvbsrc)->current_state == GST_STATE_PAUSED) {
GST_INFO_OBJECT (dvbsrc, "Setting pes filters now");
gst_dvbsrc_set_pes_filters (dvbsrc);
}
}
static void
gst_dvbsrc_set_property (GObject * _object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDvbSrc *object;
g_return_if_fail (GST_IS_DVBSRC (_object));
object = GST_DVBSRC (_object);
switch (prop_id) {
case ARG_DVBSRC_ADAPTER:
object->adapter_number = g_value_get_int (value);
break;
case ARG_DVBSRC_FRONTEND:
object->frontend_number = g_value_get_int (value);
break;
case ARG_DVBSRC_DISEQC_SRC:
if (object->diseqc_src != g_value_get_int (value)) {
object->diseqc_src = g_value_get_int (value);
object->send_diseqc = TRUE;
}
GST_INFO_OBJECT (object, "Set Property: ARG_DVBSRC_DISEQC_ID");
break;
case ARG_DVBSRC_FREQUENCY:
object->freq = g_value_get_uint (value);
GST_INFO_OBJECT (object, "Set Property: ARG_DVBSRC_FREQUENCY (%d Hz)",
object->freq);
break;
case ARG_DVBSRC_POLARITY:
{
const char *s = NULL;
s = g_value_get_string (value);
if (s != NULL) {
object->pol = (s[0] == 'h' || s[0] == 'H') ? DVB_POL_H : DVB_POL_V;
GST_INFO_OBJECT (object, "Set Property: ARG_DVBSRC_POLARITY");
GST_INFO_OBJECT (object, "\t%s", (s[0] == 'h'
|| s[0] == 'H') ? "DVB_POL_H" : "DVB_POL_V");
}
break;
}
case ARG_DVBSRC_PIDS:
{
const gchar *pid_string;
pid_string = g_value_get_string (value);
GST_INFO_OBJECT (object, "Set Property: ARG_DVBSRC_PIDS %s", pid_string);
if (pid_string)
gst_dvbsrc_set_pids (object, pid_string);
break;
}
case ARG_DVBSRC_SYM_RATE:
object->sym_rate = g_value_get_uint (value);
GST_INFO_OBJECT (object, "Set Property: ARG_DVBSRC_SYM_RATE to value %d",
object->sym_rate);
break;
case ARG_DVBSRC_BANDWIDTH_HZ:
object->bandwidth = g_value_get_uint (value);
break;
case ARG_DVBSRC_BANDWIDTH:
switch (g_value_get_enum (value)) {
case BANDWIDTH_8_MHZ:
object->bandwidth = 8000000;
break;
case BANDWIDTH_7_MHZ:
object->bandwidth = 7000000;
break;
case BANDWIDTH_6_MHZ:
object->bandwidth = 6000000;
break;
case BANDWIDTH_5_MHZ:
object->bandwidth = 5000000;
break;
case BANDWIDTH_10_MHZ:
object->bandwidth = 10000000;
break;
case BANDWIDTH_1_712_MHZ:
object->bandwidth = 1712000;
break;
default:
/* we don't know which bandwidth is set */
object->bandwidth = 0;
break;
}
break;
case ARG_DVBSRC_CODE_RATE_HP:
object->code_rate_hp = g_value_get_enum (value);
break;
case ARG_DVBSRC_CODE_RATE_LP:
object->code_rate_lp = g_value_get_enum (value);
break;
case ARG_DVBSRC_GUARD:
object->guard_interval = g_value_get_enum (value);
break;
case ARG_DVBSRC_MODULATION:
object->modulation = g_value_get_enum (value);
break;
case ARG_DVBSRC_TRANSMISSION_MODE:
object->transmission_mode = g_value_get_enum (value);
break;
case ARG_DVBSRC_HIERARCHY_INF:
object->hierarchy_information = g_value_get_enum (value);
break;
case ARG_DVBSRC_INVERSION:
object->inversion = g_value_get_enum (value);
break;
case ARG_DVBSRC_TUNE:
GST_INFO_OBJECT (object, "Set Property: ARG_DVBSRC_TUNE");
gst_dvbsrc_do_tune (object);
break;
case ARG_DVBSRC_STATS_REPORTING_INTERVAL:
object->stats_interval = g_value_get_uint (value);
object->stats_counter = 0;
break;
case ARG_DVBSRC_TIMEOUT:
object->timeout = g_value_get_uint64 (value);
break;
case ARG_DVBSRC_TUNING_TIMEOUT:
object->tuning_timeout = g_value_get_uint64 (value);
break;
case ARG_DVBSRC_DVB_BUFFER_SIZE:
object->dvb_buffer_size = g_value_get_uint (value);
break;
case ARG_DVBSRC_DELSYS:
object->delsys = g_value_get_enum (value);
break;
case ARG_DVBSRC_PILOT:
object->pilot = g_value_get_enum (value);
break;
case ARG_DVBSRC_ROLLOFF:
object->rolloff = g_value_get_enum (value);
break;
case ARG_DVBSRC_STREAM_ID:
object->stream_id = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_LAYER_ENABLED:
object->isdbt_layer_enabled = g_value_get_uint (value);
break;
case ARG_DVBSRC_ISDBT_PARTIAL_RECEPTION:
object->isdbt_partial_reception = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_SOUND_BROADCASTING:
object->isdbt_sound_broadcasting = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_SB_SUBCHANNEL_ID:
object->isdbt_sb_subchannel_id = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_SB_SEGMENT_IDX:
object->isdbt_sb_segment_idx = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_SB_SEGMENT_COUNT:
object->isdbt_sb_segment_count = g_value_get_uint (value);
break;
case ARG_DVBSRC_ISDBT_LAYERA_FEC:
object->isdbt_layera_fec = g_value_get_enum (value);
break;
case ARG_DVBSRC_ISDBT_LAYERA_MODULATION:
object->isdbt_layera_modulation = g_value_get_enum (value);
break;
case ARG_DVBSRC_ISDBT_LAYERA_SEGMENT_COUNT:
object->isdbt_layera_segment_count = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_LAYERA_TIME_INTERLEAVING:
object->isdbt_layera_time_interleaving = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_LAYERB_FEC:
object->isdbt_layerb_fec = g_value_get_enum (value);
break;
case ARG_DVBSRC_ISDBT_LAYERB_MODULATION:
object->isdbt_layerb_modulation = g_value_get_enum (value);
break;
case ARG_DVBSRC_ISDBT_LAYERB_SEGMENT_COUNT:
object->isdbt_layerb_segment_count = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_LAYERB_TIME_INTERLEAVING:
object->isdbt_layerb_time_interleaving = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_LAYERC_FEC:
object->isdbt_layerc_fec = g_value_get_enum (value);
break;
case ARG_DVBSRC_ISDBT_LAYERC_MODULATION:
object->isdbt_layerc_modulation = g_value_get_enum (value);
break;
case ARG_DVBSRC_ISDBT_LAYERC_SEGMENT_COUNT:
object->isdbt_layerc_segment_count = g_value_get_int (value);
break;
case ARG_DVBSRC_ISDBT_LAYERC_TIME_INTERLEAVING:
object->isdbt_layerc_time_interleaving = g_value_get_int (value);
break;
case ARG_DVBSRC_LNB_SLOF:
object->lnb_slof = g_value_get_uint (value);
break;
case ARG_DVBSRC_LNB_LOF1:
object->lnb_lof1 = g_value_get_uint (value);
break;
case ARG_DVBSRC_LNB_LOF2:
object->lnb_lof2 = g_value_get_uint (value);
break;
case ARG_DVBSRC_INTERLEAVING:
object->interleaving = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gst_dvbsrc_get_property (GObject * _object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDvbSrc *object;
g_return_if_fail (GST_IS_DVBSRC (_object));
object = GST_DVBSRC (_object);
switch (prop_id) {
case ARG_DVBSRC_ADAPTER:
g_value_set_int (value, object->adapter_number);
break;
case ARG_DVBSRC_FRONTEND:
g_value_set_int (value, object->frontend_number);
break;
case ARG_DVBSRC_FREQUENCY:
g_value_set_uint (value, object->freq);
break;
case ARG_DVBSRC_POLARITY:
if (object->pol == DVB_POL_H)
g_value_set_static_string (value, "H");
else
g_value_set_static_string (value, "V");
break;
case ARG_DVBSRC_SYM_RATE:
g_value_set_uint (value, object->sym_rate);
break;
case ARG_DVBSRC_DISEQC_SRC:
g_value_set_int (value, object->diseqc_src);
break;
case ARG_DVBSRC_BANDWIDTH_HZ:
g_value_set_uint (value, object->bandwidth);
break;
case ARG_DVBSRC_BANDWIDTH:{
int tmp;
if (!object->bandwidth)
tmp = BANDWIDTH_AUTO;
else if (object->bandwidth <= 1712000)
tmp = BANDWIDTH_1_712_MHZ;
else if (object->bandwidth <= 5000000)
tmp = BANDWIDTH_5_MHZ;
else if (object->bandwidth <= 6000000)
tmp = BANDWIDTH_6_MHZ;
else if (object->bandwidth <= 7000000)
tmp = BANDWIDTH_7_MHZ;
else if (object->bandwidth <= 8000000)
tmp = BANDWIDTH_8_MHZ;
else if (object->bandwidth <= 10000000)
tmp = BANDWIDTH_10_MHZ;
else
tmp = BANDWIDTH_AUTO;
g_value_set_enum (value, tmp);
break;
}
case ARG_DVBSRC_CODE_RATE_HP:
g_value_set_enum (value, object->code_rate_hp);
break;
case ARG_DVBSRC_CODE_RATE_LP:
g_value_set_enum (value, object->code_rate_lp);
break;
case ARG_DVBSRC_GUARD:
g_value_set_enum (value, object->guard_interval);
break;
case ARG_DVBSRC_MODULATION:
g_value_set_enum (value, object->modulation);
break;
case ARG_DVBSRC_TRANSMISSION_MODE:
g_value_set_enum (value, object->transmission_mode);
break;
case ARG_DVBSRC_HIERARCHY_INF:
g_value_set_enum (value, object->hierarchy_information);
break;
case ARG_DVBSRC_INVERSION:
g_value_set_enum (value, object->inversion);
break;
case ARG_DVBSRC_STATS_REPORTING_INTERVAL:
g_value_set_uint (value, object->stats_interval);
break;
case ARG_DVBSRC_TIMEOUT:
g_value_set_uint64 (value, object->timeout);
break;
case ARG_DVBSRC_TUNING_TIMEOUT:
g_value_set_uint64 (value, object->tuning_timeout);
break;
case ARG_DVBSRC_DVB_BUFFER_SIZE:
g_value_set_uint (value, object->dvb_buffer_size);
break;
case ARG_DVBSRC_DELSYS:
g_value_set_enum (value, object->delsys);
break;
case ARG_DVBSRC_PILOT:
g_value_set_enum (value, object->pilot);
break;
case ARG_DVBSRC_ROLLOFF:
g_value_set_enum (value, object->rolloff);
break;
case ARG_DVBSRC_STREAM_ID:
g_value_set_int (value, object->stream_id);
break;
case ARG_DVBSRC_ISDBT_LAYER_ENABLED:
g_value_set_uint (value, object->isdbt_layer_enabled);
break;
case ARG_DVBSRC_ISDBT_PARTIAL_RECEPTION:
g_value_set_int (value, object->isdbt_partial_reception);
break;
case ARG_DVBSRC_ISDBT_SOUND_BROADCASTING:
g_value_set_int (value, object->isdbt_sound_broadcasting);
break;
case ARG_DVBSRC_ISDBT_SB_SUBCHANNEL_ID:
g_value_set_int (value, object->isdbt_sb_subchannel_id);
break;
case ARG_DVBSRC_ISDBT_SB_SEGMENT_IDX:
g_value_set_int (value, object->isdbt_sb_segment_idx);
break;
case ARG_DVBSRC_ISDBT_SB_SEGMENT_COUNT:
g_value_set_uint (value, object->isdbt_sb_segment_count);
break;
case ARG_DVBSRC_ISDBT_LAYERA_FEC:
g_value_set_enum (value, object->isdbt_layera_fec);
break;
case ARG_DVBSRC_ISDBT_LAYERA_MODULATION:
g_value_set_enum (value, object->isdbt_layera_modulation);
break;
case ARG_DVBSRC_ISDBT_LAYERA_SEGMENT_COUNT:
g_value_set_int (value, object->isdbt_layera_segment_count);
break;
case ARG_DVBSRC_ISDBT_LAYERA_TIME_INTERLEAVING:
g_value_set_int (value, object->isdbt_layera_time_interleaving);
break;
case ARG_DVBSRC_ISDBT_LAYERB_FEC:
g_value_set_enum (value, object->isdbt_layerb_fec);
break;
case ARG_DVBSRC_ISDBT_LAYERB_MODULATION:
g_value_set_enum (value, object->isdbt_layerb_modulation);
break;
case ARG_DVBSRC_ISDBT_LAYERB_SEGMENT_COUNT:
g_value_set_int (value, object->isdbt_layerb_segment_count);
break;
case ARG_DVBSRC_ISDBT_LAYERB_TIME_INTERLEAVING:
g_value_set_int (value, object->isdbt_layerb_time_interleaving);
break;
case ARG_DVBSRC_ISDBT_LAYERC_FEC:
g_value_set_enum (value, object->isdbt_layerc_fec);
break;
case ARG_DVBSRC_ISDBT_LAYERC_MODULATION:
g_value_set_enum (value, object->isdbt_layerc_modulation);
break;
case ARG_DVBSRC_ISDBT_LAYERC_SEGMENT_COUNT:
g_value_set_int (value, object->isdbt_layerc_segment_count);
break;
case ARG_DVBSRC_ISDBT_LAYERC_TIME_INTERLEAVING:
g_value_set_int (value, object->isdbt_layerc_time_interleaving);
break;
case ARG_DVBSRC_LNB_SLOF:
g_value_set_uint (value, object->lnb_slof);
break;
case ARG_DVBSRC_LNB_LOF1:
g_value_set_uint (value, object->lnb_lof1);
break;
case ARG_DVBSRC_LNB_LOF2:
g_value_set_uint (value, object->lnb_lof2);
break;
case ARG_DVBSRC_INTERLEAVING:
g_value_set_enum (value, object->interleaving);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static gboolean
gst_dvbsrc_close_devices (GstDvbSrc * object)
{
gst_dvbsrc_unset_pes_filters (object);
close (object->fd_dvr);
object->fd_dvr = -1;
close (object->fd_frontend);
object->fd_frontend = -1;
return TRUE;
}
static gboolean
gst_dvbsrc_check_delsys (struct dtv_property *prop, guchar delsys)
{
int i;
for (i = 0; i < prop->u.buffer.len; i++) {
if (prop->u.buffer.data[i] == delsys)
return TRUE;
}
GST_LOG ("Adapter does not support delsys: %d", delsys);
return FALSE;
}
static gboolean
gst_dvbsrc_open_frontend (GstDvbSrc * object, gboolean writable)
{
struct dvb_frontend_info fe_info;
struct dtv_properties props;
struct dtv_property dvb_prop[1];
gchar *frontend_dev;
GstStructure *adapter_structure;
char *adapter_name = NULL;
gint err;
frontend_dev = g_strdup_printf ("/dev/dvb/adapter%d/frontend%d",
object->adapter_number, object->frontend_number);
GST_INFO_OBJECT (object, "Using frontend device: %s", frontend_dev);
/* open frontend */
LOOP_WHILE_EINTR (object->fd_frontend,
open (frontend_dev, writable ? O_RDWR : O_RDONLY));
if (object->fd_frontend < 0) {
switch (errno) {
case ENOENT:
GST_ELEMENT_ERROR (object, RESOURCE, NOT_FOUND,
(_("Device \"%s\" does not exist."), frontend_dev), (NULL));
break;
default:
GST_ELEMENT_ERROR (object, RESOURCE, OPEN_READ_WRITE,
(_("Could not open frontend device \"%s\"."), frontend_dev),
GST_ERROR_SYSTEM);
break;
}
g_free (frontend_dev);
return FALSE;
}
GST_DEBUG_OBJECT (object, "Device opened, querying information");
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend, FE_GET_INFO, &fe_info));
if (err) {
GST_ELEMENT_ERROR (object, RESOURCE, SETTINGS,
(_("Could not get settings from frontend device \"%s\"."),
frontend_dev), GST_ERROR_SYSTEM);
close (object->fd_frontend);
g_free (frontend_dev);
return FALSE;
}
GST_DEBUG_OBJECT (object, "check delivery systems");
dvb_prop[0].cmd = DTV_ENUM_DELSYS;
props.num = 1;
props.props = dvb_prop;
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend, FE_GET_PROPERTY, &props));
if (err) {
GST_ELEMENT_ERROR (object, RESOURCE, SETTINGS,
(_("Cannot enumerate delivery systems from frontend device \"%s\"."),
frontend_dev), GST_ERROR_SYSTEM);
close (object->fd_frontend);
g_free (frontend_dev);
return FALSE;
}
GST_DEBUG_OBJECT (object, "Got information about adapter : %s", fe_info.name);
adapter_name = g_strdup (fe_info.name);
adapter_structure = gst_structure_new ("dvb-adapter",
"name", G_TYPE_STRING, adapter_name,
/* Capability supported auto params */
"auto-inversion", G_TYPE_BOOLEAN, fe_info.caps & FE_CAN_INVERSION_AUTO,
"auto-qam", G_TYPE_BOOLEAN, fe_info.caps & FE_CAN_QAM_AUTO,
"auto-transmission-mode", G_TYPE_BOOLEAN,
fe_info.caps & FE_CAN_TRANSMISSION_MODE_AUTO, "auto-guard-interval",
G_TYPE_BOOLEAN, fe_info.caps & FE_CAN_GUARD_INTERVAL_AUTO,
"auto-hierarchy", G_TYPE_BOOLEAN, fe_info.caps & FE_CAN_HIERARCHY_AUTO,
"auto-fec", G_TYPE_BOOLEAN, fe_info.caps & FE_CAN_FEC_AUTO, NULL);
/* Capability delivery systems */
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBC_ANNEX_A)) {
gst_structure_set (adapter_structure, "dvb-c-a", G_TYPE_STRING,
"DVB-C ANNEX A", NULL);
object->best_guess_delsys = SYS_DVBC_ANNEX_A;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBC_ANNEX_B)) {
gst_structure_set (adapter_structure, "dvb-c-b", G_TYPE_STRING,
"DVB-C ANNEX C", NULL);
object->best_guess_delsys = SYS_DVBC_ANNEX_B;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBT)) {
gst_structure_set (adapter_structure, "dvb-t", G_TYPE_STRING, "DVB-T",
NULL);
object->best_guess_delsys = SYS_DVBT;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DSS)) {
gst_structure_set (adapter_structure, "dss", G_TYPE_STRING, "DSS", NULL);
object->best_guess_delsys = SYS_DSS;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBS)) {
gst_structure_set (adapter_structure, "dvb-s", G_TYPE_STRING, "DVB-S",
NULL);
object->best_guess_delsys = SYS_DVBS;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBS2)) {
gst_structure_set (adapter_structure, "dvb-s2", G_TYPE_STRING, "DVB-S2",
NULL);
object->best_guess_delsys = SYS_DVBS2;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBH)) {
gst_structure_set (adapter_structure, "dvb-h", G_TYPE_STRING, "DVB-H",
NULL);
object->best_guess_delsys = SYS_DVBH;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_ISDBT)) {
gst_structure_set (adapter_structure, "isdb-t", G_TYPE_STRING, "ISDB-T",
NULL);
object->best_guess_delsys = SYS_ISDBT;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_ISDBS)) {
gst_structure_set (adapter_structure, "isdb-s", G_TYPE_STRING, "ISDB-S",
NULL);
object->best_guess_delsys = SYS_ISDBS;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_ISDBC)) {
gst_structure_set (adapter_structure, "isdb-c", G_TYPE_STRING, "ISDB-C",
NULL);
object->best_guess_delsys = SYS_ISDBC;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_ATSC)) {
gst_structure_set (adapter_structure, "atsc", G_TYPE_STRING, "ATSC", NULL);
object->best_guess_delsys = SYS_ATSC;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_ATSCMH)) {
gst_structure_set (adapter_structure, "atsc-mh", G_TYPE_STRING, "ATSC-MH",
NULL);
object->best_guess_delsys = SYS_ATSCMH;
}
#if HAVE_V5_MINOR(7)
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DTMB)) {
gst_structure_set (adapter_structure, "dtmb", G_TYPE_STRING, "DTMB", NULL);
object->best_guess_delsys = SYS_DTMB;
}
#endif
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_CMMB)) {
gst_structure_set (adapter_structure, "cmmb", G_TYPE_STRING, "CMMB", NULL);
object->best_guess_delsys = SYS_CMMB;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DAB)) {
gst_structure_set (adapter_structure, "dab", G_TYPE_STRING, "DAB", NULL);
object->best_guess_delsys = SYS_DAB;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBT2)) {
gst_structure_set (adapter_structure, "dvb-t2", G_TYPE_STRING, "DVB-T2",
NULL);
object->best_guess_delsys = SYS_DVBT2;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_TURBO)) {
gst_structure_set (adapter_structure, "turbo", G_TYPE_STRING, "TURBO",
NULL);
object->best_guess_delsys = SYS_TURBO;
}
if (gst_dvbsrc_check_delsys (&dvb_prop[0], SYS_DVBC_ANNEX_C)) {
gst_structure_set (adapter_structure, "dvb-c-c", G_TYPE_STRING,
"DVB-C ANNEX C", NULL);
object->best_guess_delsys = SYS_DVBC_ANNEX_C;
}
GST_INFO_OBJECT (object, "DVB card: %s ", adapter_name);
GST_TRACE_OBJECT (object, "%s description: %" GST_PTR_FORMAT, adapter_name,
adapter_structure);
gst_element_post_message (GST_ELEMENT_CAST (object), gst_message_new_element
(GST_OBJECT (object), adapter_structure));
g_free (frontend_dev);
g_free (adapter_name);
return TRUE;
}
static gboolean
gst_dvbsrc_open_dvr (GstDvbSrc * object)
{
gchar *dvr_dev;
gint err;
dvr_dev = g_strdup_printf ("/dev/dvb/adapter%d/dvr%d",
object->adapter_number, object->frontend_number);
GST_INFO_OBJECT (object, "Using dvr device: %s", dvr_dev);
/* open DVR */
if ((object->fd_dvr = open (dvr_dev, O_RDONLY | O_NONBLOCK)) < 0) {
switch (errno) {
case ENOENT:
GST_ELEMENT_ERROR (object, RESOURCE, NOT_FOUND,
(_("Device \"%s\" does not exist."), dvr_dev), (NULL));
break;
default:
GST_ELEMENT_ERROR (object, RESOURCE, OPEN_READ,
(_("Could not open file \"%s\" for reading."), dvr_dev),
GST_ERROR_SYSTEM);
break;
}
g_free (dvr_dev);
return FALSE;
}
g_free (dvr_dev);
GST_INFO_OBJECT (object, "Setting DVB kernel buffer size to %d ",
object->dvb_buffer_size);
LOOP_WHILE_EINTR (err, ioctl (object->fd_dvr, DMX_SET_BUFFER_SIZE,
object->dvb_buffer_size));
if (err) {
GST_INFO_OBJECT (object, "ioctl DMX_SET_BUFFER_SIZE failed (%d)", errno);
return FALSE;
}
return TRUE;
}
static void
gst_dvbsrc_finalize (GObject * _object)
{
GstDvbSrc *object;
GST_DEBUG_OBJECT (_object, "gst_dvbsrc_finalize");
g_return_if_fail (GST_IS_DVBSRC (_object));
object = GST_DVBSRC (_object);
/* freeing the mutex segfaults somehow */
g_mutex_clear (&object->tune_mutex);
if (G_OBJECT_CLASS (parent_class)->finalize)
G_OBJECT_CLASS (parent_class)->finalize (_object);
}
/*
******************************
* *
* Plugin Realization *
* *
******************************
*/
/* entry point to initialize the plug-in
* initialize the plug-in itself
* register the element factories and pad templates
* register the features
*/
gboolean
gst_dvbsrc_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gstdvbsrc_debug, "dvbsrc", 0, "DVB Source Element");
return gst_element_register (plugin, "dvbsrc", GST_RANK_NONE,
GST_TYPE_DVBSRC);
}
static GstFlowReturn
gst_dvbsrc_read_device (GstDvbSrc * object, int size, GstBuffer ** buffer)
{
gint count = 0;
gint ret_val = 0;
GstBuffer *buf = gst_buffer_new_and_alloc (size);
GstClockTime timeout = object->timeout * GST_USECOND;
GstMapInfo map;
g_return_val_if_fail (GST_IS_BUFFER (buf), GST_FLOW_ERROR);
if (object->fd_dvr < 0)
return GST_FLOW_ERROR;
gst_buffer_map (buf, &map, GST_MAP_WRITE);
while (count < size) {
ret_val = gst_poll_wait (object->poll, timeout);
GST_LOG_OBJECT (object, "select returned %d", ret_val);
if (G_UNLIKELY (ret_val < 0)) {
if (errno == EBUSY)
goto stopped;
else if (errno == EINTR)
continue;
else
goto select_error;
} else if (G_UNLIKELY (!ret_val)) {
/* timeout, post element message */
gst_element_post_message (GST_ELEMENT_CAST (object),
gst_message_new_element (GST_OBJECT (object),
gst_structure_new_empty ("dvb-read-failure")));
} else {
int nread = read (object->fd_dvr, map.data + count, size - count);
if (G_UNLIKELY (nread < 0)) {
GST_WARNING_OBJECT
(object,
"Unable to read from device: /dev/dvb/adapter%d/dvr%d (%d)",
object->adapter_number, object->frontend_number, errno);
gst_element_post_message (GST_ELEMENT_CAST (object),
gst_message_new_element (GST_OBJECT (object),
gst_structure_new_empty ("dvb-read-failure")));
} else
count = count + nread;
}
}
gst_buffer_unmap (buf, &map);
gst_buffer_resize (buf, 0, count);
*buffer = buf;
return GST_FLOW_OK;
stopped:
{
GST_DEBUG_OBJECT (object, "stop called");
gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
return GST_FLOW_FLUSHING;
}
select_error:
{
GST_ELEMENT_ERROR (object, RESOURCE, READ, (NULL),
("select error %d: %s (%d)", ret_val, g_strerror (errno), errno));
gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_dvbsrc_create (GstPushSrc * element, GstBuffer ** buf)
{
gint buffer_size;
GstFlowReturn retval = GST_FLOW_ERROR;
GstDvbSrc *object;
object = GST_DVBSRC (element);
GST_LOG ("fd_dvr: %d", object->fd_dvr);
buffer_size = DEFAULT_BUFFER_SIZE;
/* device can not be tuned during read */
g_mutex_lock (&object->tune_mutex);
if (object->fd_dvr > -1) {
/* --- Read TS from DVR device --- */
GST_DEBUG_OBJECT (object, "Reading from DVR device");
retval = gst_dvbsrc_read_device (object, buffer_size, buf);
if (object->stats_interval &&
++object->stats_counter == object->stats_interval) {
gst_dvbsrc_output_frontend_stats (object);
object->stats_counter = 0;
}
}
g_mutex_unlock (&object->tune_mutex);
return retval;
}
static GstStateChangeReturn
gst_dvbsrc_change_state (GstElement * element, GstStateChange transition)
{
GstDvbSrc *src;
GstStateChangeReturn ret;
src = GST_DVBSRC (element);
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
/* open frontend then close it again, just so caps sent */
gst_dvbsrc_open_frontend (src, FALSE);
if (src->fd_frontend) {
close (src->fd_frontend);
}
break;
default:
break;
}
return ret;
}
static gboolean
gst_dvbsrc_start (GstBaseSrc * bsrc)
{
GstDvbSrc *src = GST_DVBSRC (bsrc);
gst_dvbsrc_open_frontend (src, TRUE);
if (!gst_dvbsrc_tune (src)) {
GST_ERROR_OBJECT (src, "Not able to lock on to the dvb channel");
gst_dvbsrc_unset_pes_filters (src);
close (src->fd_frontend);
return FALSE;
}
if (!gst_dvbsrc_open_dvr (src)) {
GST_ERROR_OBJECT (src, "Not able to open dvr_device");
/* unset filters also */
gst_dvbsrc_unset_pes_filters (src);
close (src->fd_frontend);
return FALSE;
}
if (!(src->poll = gst_poll_new (TRUE))) {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
("could not create an fdset: %s (%d)", g_strerror (errno), errno));
/* unset filters also */
gst_dvbsrc_unset_pes_filters (src);
close (src->fd_frontend);
return FALSE;
} else {
gst_poll_fd_init (&src->poll_fd_dvr);
src->poll_fd_dvr.fd = src->fd_dvr;
gst_poll_add_fd (src->poll, &src->poll_fd_dvr);
gst_poll_fd_ctl_read (src->poll, &src->poll_fd_dvr, TRUE);
}
return TRUE;
}
static gboolean
gst_dvbsrc_stop (GstBaseSrc * bsrc)
{
GstDvbSrc *src = GST_DVBSRC (bsrc);
gst_dvbsrc_close_devices (src);
if (src->poll) {
gst_poll_free (src->poll);
src->poll = NULL;
}
return TRUE;
}
static gboolean
gst_dvbsrc_unlock (GstBaseSrc * bsrc)
{
GstDvbSrc *src = GST_DVBSRC (bsrc);
gst_poll_set_flushing (src->poll, TRUE);
return TRUE;
}
static gboolean
gst_dvbsrc_unlock_stop (GstBaseSrc * bsrc)
{
GstDvbSrc *src = GST_DVBSRC (bsrc);
gst_poll_set_flushing (src->poll, FALSE);
return TRUE;
}
static gboolean
gst_dvbsrc_is_seekable (GstBaseSrc * bsrc)
{
return FALSE;
}
static gboolean
gst_dvbsrc_is_valid_modulation (guint delsys, guint mod)
{
/* FIXME: check valid modulations for other broadcast standards */
switch (delsys) {
case SYS_ISDBT:
if (mod == QAM_AUTO || mod == QPSK || mod == QAM_16 ||
mod == QAM_64 || mod == DQPSK)
return TRUE;
break;
default:
GST_FIXME ("No delsys/modulation sanity checks implemented for this "
"delivery system");
return TRUE;
}
return FALSE;
}
static gboolean
gst_dvbsrc_get_size (GstBaseSrc * src, guint64 * size)
{
return FALSE;
}
static void
gst_dvbsrc_do_tune (GstDvbSrc * src)
{
/* if we are in paused/playing state tune now, otherwise in ready
* to paused state change */
if (GST_STATE (src) > GST_STATE_READY)
gst_dvbsrc_tune (src);
}
static void
gst_dvbsrc_output_frontend_stats (GstDvbSrc * src)
{
fe_status_t status;
guint16 snr, _signal;
guint32 ber, bad_blks;
GstMessage *message;
GstStructure *structure;
int fe_fd = src->fd_frontend;
gint err;
LOOP_WHILE_EINTR (err, ioctl (fe_fd, FE_READ_STATUS, &status));
if (err)
goto error_out;
LOOP_WHILE_EINTR (err, ioctl (fe_fd, FE_READ_SIGNAL_STRENGTH, &_signal));
if (err)
goto error_out;
LOOP_WHILE_EINTR (err, ioctl (fe_fd, FE_READ_SNR, &snr));
if (err)
goto error_out;
LOOP_WHILE_EINTR (err, ioctl (fe_fd, FE_READ_BER, &ber));
if (err)
goto error_out;
LOOP_WHILE_EINTR (err, ioctl (fe_fd, FE_READ_UNCORRECTED_BLOCKS, &bad_blks));
if (err)
goto error_out;
structure = gst_structure_new ("dvb-frontend-stats", "status", G_TYPE_INT,
status, "signal", G_TYPE_INT, _signal, "snr", G_TYPE_INT, snr,
"ber", G_TYPE_INT, ber, "unc", G_TYPE_INT, bad_blks,
"lock", G_TYPE_BOOLEAN, status & FE_HAS_LOCK, NULL);
message = gst_message_new_element (GST_OBJECT (src), structure);
gst_element_post_message (GST_ELEMENT (src), message);
return;
error_out:
GST_WARNING_OBJECT (src, "Failed to get statistics from the device: %s",
g_strerror (errno));
}
struct diseqc_cmd
{
struct dvb_diseqc_master_cmd cmd;
guint32 wait;
};
static void
diseqc_send_msg (int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd,
fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
{
gint err;
LOOP_WHILE_EINTR (err, ioctl (fd, FE_SET_TONE, SEC_TONE_OFF));
if (err) {
GST_ERROR ("Setting tone to off failed");
return;
}
LOOP_WHILE_EINTR (err, ioctl (fd, FE_SET_VOLTAGE, v));
if (err) {
GST_ERROR ("Setting voltage failed");
return;
}
g_usleep (15 * 1000);
GST_LOG ("diseqc: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", cmd->cmd.msg[0],
cmd->cmd.msg[1], cmd->cmd.msg[2], cmd->cmd.msg[3], cmd->cmd.msg[4],
cmd->cmd.msg[5]);
LOOP_WHILE_EINTR (err, ioctl (fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd));
if (err) {
GST_ERROR ("Sending DiSEqC command failed");
return;
}
g_usleep (cmd->wait * 1000);
g_usleep (15 * 1000);
LOOP_WHILE_EINTR (err, ioctl (fd, FE_DISEQC_SEND_BURST, b));
if (err) {
GST_ERROR ("Sending burst failed");
return;
}
g_usleep (15 * 1000);
LOOP_WHILE_EINTR (err, ioctl (fd, FE_SET_TONE, t));
if (err) {
GST_ERROR ("Setting tone failed");
return;
}
}
/* digital satellite equipment control,
* specification is available from http://www.eutelsat.com/
*/
static void
diseqc (int secfd, int sat_no, int voltage, int tone)
{
struct diseqc_cmd cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
/* param: high nibble: reset bits, low nibble set bits,
* bits are: option, position, polarizaion, band
*/
cmd.cmd.msg[3] =
0xf0 | (((sat_no * 4) & 0x0f) | (tone == SEC_TONE_ON ? 1 : 0) |
(voltage == SEC_VOLTAGE_13 ? 0 : 2));
/* send twice because some DiSEqC switches do not respond correctly the
* first time */
diseqc_send_msg (secfd, voltage, &cmd, tone,
sat_no % 2 ? SEC_MINI_B : SEC_MINI_A);
diseqc_send_msg (secfd, voltage, &cmd, tone,
sat_no % 2 ? SEC_MINI_B : SEC_MINI_A);
}
inline static void
set_prop (struct dtv_property *props, int *n, guint32 cmd, guint32 data)
{
if (*n == NUM_DTV_PROPS) {
g_critical ("Index out of bounds");
} else {
props[*n].cmd = cmd;
props[(*n)++].u.data = data;
}
}
static gboolean
gst_dvbsrc_tune_fe (GstDvbSrc * object)
{
GstPoll *poll_set;
GstPollFD fe_fd;
fe_status_t status;
struct dtv_properties props;
struct dtv_property dvb_prop[NUM_DTV_PROPS];
GstClockTimeDiff elapsed_time, timeout_step = 500 * GST_MSECOND;
GstClockTime start;
gint err;
GST_DEBUG_OBJECT (object, "Starting the frontend tuning process");
if (object->fd_frontend < 0) {
GST_INFO_OBJECT (object, "Frontend not open: tuning later");
return FALSE;
}
/* If there's no delivery system set yet, proceed with the autodetected
* one, otherwise confirm the one set is supported */
if (object->delsys == SYS_UNDEFINED)
object->delsys = object->best_guess_delsys;
else {
GST_DEBUG_OBJECT (object, "Confirming delsys '%u' is supported",
object->delsys);
dvb_prop[0].cmd = DTV_ENUM_DELSYS;
props.num = 1;
props.props = dvb_prop;
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend,
FE_GET_PROPERTY, &props));
if (err) {
GST_WARNING_OBJECT (object, "Error enumerating delsys: %s",
g_strerror (errno));
return FALSE;
}
if (!gst_dvbsrc_check_delsys (&dvb_prop[0], object->delsys)) {
GST_WARNING_OBJECT (object, "Adapter does not support delsys '%u'",
object->delsys);
return FALSE;
}
}
gst_dvbsrc_unset_pes_filters (object);
g_mutex_lock (&object->tune_mutex);
gst_poll_fd_init (&fe_fd);
fe_fd.fd = object->fd_frontend;
poll_set = gst_poll_new (TRUE);
if (!gst_poll_add_fd (poll_set, &fe_fd)) {
GST_WARNING_OBJECT (object, "Could not add frontend fd to poll set");
goto fail;
}
gst_poll_fd_ctl_read (poll_set, &fe_fd, TRUE);
memset (dvb_prop, 0, sizeof (dvb_prop));
dvb_prop[0].cmd = DTV_CLEAR;
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend, FE_SET_PROPERTY, &props));
if (err) {
GST_WARNING_OBJECT (object, "Error resetting tuner: %s",
g_strerror (errno));
}
memset (dvb_prop, 0, sizeof (dvb_prop));
if (!gst_dvbsrc_set_fe_params (object, &props)) {
GST_WARNING_OBJECT (object, "Could not set frontend params");
goto fail;
}
GST_DEBUG_OBJECT (object, "Setting %d properties", props.num);
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend, FE_SET_PROPERTY, &props));
if (err) {
GST_WARNING_OBJECT (object, "Error tuning channel: %s (%d)",
g_strerror (errno), errno);
goto fail;
}
g_signal_emit (object, gst_dvbsrc_signals[SIGNAL_TUNING_START], 0);
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend, FE_READ_STATUS, &status));
if (err) {
GST_WARNING_OBJECT (object, "Failed querying frontend for tuning status:"
" %s (%d)", g_strerror (errno), errno);
goto fail_with_signal;
}
/* signal locking loop */
elapsed_time = 0;
start = gst_util_get_timestamp ();
while (!(status & FE_HAS_LOCK) && elapsed_time <= object->tuning_timeout) {
if (gst_poll_wait (poll_set, timeout_step) == -1)
goto fail_with_signal;
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend, FE_READ_STATUS,
&status));
if (err) {
GST_WARNING_OBJECT (object, "Failed querying frontend for tuning status"
" %s (%d)", g_strerror (errno), errno);
goto fail_with_signal;
}
gst_dvbsrc_output_frontend_stats (object);
/* keep retrying forever if tuning_timeout = 0 */
if (object->tuning_timeout)
elapsed_time = GST_CLOCK_DIFF (start, gst_util_get_timestamp ());
GST_LOG_OBJECT (object,
"Tuning. Time elapsed %" GST_STIME_FORMAT " Limit %" GST_TIME_FORMAT,
GST_STIME_ARGS (elapsed_time), GST_TIME_ARGS (object->tuning_timeout));
}
if (!(status & FE_HAS_LOCK)) {
GST_WARNING_OBJECT (object,
"Unable to lock on signal at desired frequency");
goto fail_with_signal;
}
GST_LOG_OBJECT (object, "status == 0x%02x", status);
g_signal_emit (object, gst_dvbsrc_signals[SIGNAL_TUNING_DONE], 0);
GST_DEBUG_OBJECT (object, "Successfully set frontend tuning params");
gst_poll_free (poll_set);
g_mutex_unlock (&object->tune_mutex);
return TRUE;
fail_with_signal:
g_signal_emit (object, gst_dvbsrc_signals[SIGNAL_TUNING_FAIL], 0);
fail:
GST_WARNING_OBJECT (object, "Could not tune to desired frequency");
gst_poll_free (poll_set);
g_mutex_unlock (&object->tune_mutex);
return FALSE;
}
static gboolean
gst_dvbsrc_set_fe_params (GstDvbSrc * object, struct dtv_properties *props)
{
fe_sec_voltage_t voltage;
unsigned int freq = object->freq;
unsigned int sym_rate = object->sym_rate * 1000;
int inversion = object->inversion;
int n;
gint err;
/* first 3 entries are reserved */
n = 3;
/**
* We are not dropping out but issuing a warning in case of wrong
* parameter combinations as failover behavior should be mandated
* by the driver. Worst case scenario it will just fail at tuning.
*/
switch (object->delsys) {
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
if (freq > 2200000) {
/* this must be an absolute frequency */
if (freq < object->lnb_slof) {
freq -= object->lnb_lof1;
object->tone = SEC_TONE_OFF;
} else {
freq -= object->lnb_lof2;
object->tone = SEC_TONE_ON;
}
}
inversion = INVERSION_AUTO;
set_prop (props->props, &n, DTV_SYMBOL_RATE, sym_rate);
set_prop (props->props, &n, DTV_INNER_FEC, object->code_rate_hp);
GST_INFO_OBJECT (object,
"Tuning DVB-S/DVB-S2/Turbo to L-Band:%u, Pol:%d, srate=%u, 22kHz=%s",
freq, object->pol, sym_rate,
object->tone == SEC_TONE_ON ? "on" : "off");
if (object->pol == DVB_POL_H)
voltage = SEC_VOLTAGE_18;
else
voltage = SEC_VOLTAGE_13;
if (object->diseqc_src == -1 || object->send_diseqc == FALSE) {
set_prop (props->props, &n, DTV_VOLTAGE, voltage);
/* DTV_TONE not yet implemented
* set_prop (fe_props_array, &n, DTV_TONE, object->tone) */
LOOP_WHILE_EINTR (err, ioctl (object->fd_frontend, FE_SET_TONE,
object->tone));
if (err) {
GST_WARNING_OBJECT (object, "Couldn't set tone: %s",
g_strerror (errno));
}
} else {
GST_DEBUG_OBJECT (object, "Sending DiSEqC");
diseqc (object->fd_frontend, object->diseqc_src, voltage, object->tone);
/* Once DiSEqC source is set, do not set it again until
* app decides to change it
* object->send_diseqc = FALSE; */
}
if ((object->delsys == SYS_DVBS2) || (object->delsys == SYS_TURBO))
set_prop (props->props, &n, DTV_MODULATION, object->modulation);
if (object->delsys == SYS_DVBS2) {
set_prop (props->props, &n, DTV_PILOT, object->pilot);
set_prop (props->props, &n, DTV_ROLLOFF, object->rolloff);
set_prop (props->props, &n, DTV_STREAM_ID, object->stream_id);
}
break;
case SYS_DVBT:
case SYS_DVBT2:
if (object->delsys == SYS_DVBT) {
if (object->transmission_mode != TRANSMISSION_MODE_AUTO &&
object->transmission_mode != TRANSMISSION_MODE_2K &&
object->transmission_mode != TRANSMISSION_MODE_8K) {
GST_WARNING_OBJECT (object, "Wrong DVB-T parameter combination: "
"transmission mode should be either AUTO, 2K or 8K");
}
if (object->bandwidth != 6000000 && object->bandwidth != 7000000 &&
object->bandwidth != 8000000) {
GST_WARNING_OBJECT (object, "Wrong DVB-T parameter value: bandwidth "
"is %d but only 6, 7 and 8 MHz are allowed", object->bandwidth);
}
} else if (object->delsys == SYS_DVBT2) {
if (object->transmission_mode != TRANSMISSION_MODE_AUTO &&
object->transmission_mode != TRANSMISSION_MODE_1K &&
object->transmission_mode != TRANSMISSION_MODE_2K &&
object->transmission_mode != TRANSMISSION_MODE_4K &&
object->transmission_mode != TRANSMISSION_MODE_8K &&
object->transmission_mode != TRANSMISSION_MODE_16K &&
object->transmission_mode != TRANSMISSION_MODE_32K) {
GST_WARNING_OBJECT (object, "Wrong DVB-T2 parameter combination: "
"transmission mode should be either AUTO, 1K, 2K, 4K, 8K, 16K "
"or 32K");
}
}
set_prop (props->props, &n, DTV_BANDWIDTH_HZ, object->bandwidth);
set_prop (props->props, &n, DTV_CODE_RATE_HP, object->code_rate_hp);
set_prop (props->props, &n, DTV_CODE_RATE_LP, object->code_rate_lp);
set_prop (props->props, &n, DTV_MODULATION, object->modulation);
set_prop (props->props, &n, DTV_TRANSMISSION_MODE,
object->transmission_mode);
set_prop (props->props, &n, DTV_GUARD_INTERVAL, object->guard_interval);
set_prop (props->props, &n, DTV_HIERARCHY, object->hierarchy_information);
if (object->delsys == SYS_DVBT2) {
set_prop (props->props, &n, DTV_STREAM_ID, object->stream_id);
}
GST_INFO_OBJECT (object, "Tuning DVB-T/DVB_T2 to %d Hz", freq);
break;
case SYS_DVBC_ANNEX_A:
case SYS_DVBC_ANNEX_B:
#if HAVE_V5_MINOR(6)
case SYS_DVBC_ANNEX_C:
#endif
GST_INFO_OBJECT (object, "Tuning DVB-C/ClearCable to %d, srate=%d",
freq, sym_rate);
set_prop (props->props, &n, DTV_MODULATION, object->modulation);
if (object->delsys != SYS_DVBC_ANNEX_B) {
set_prop (props->props, &n, DTV_INNER_FEC, object->code_rate_hp);
set_prop (props->props, &n, DTV_SYMBOL_RATE, sym_rate);
}
break;
case SYS_ATSC:
GST_INFO_OBJECT (object, "Tuning ATSC to %d", freq);
set_prop (props->props, &n, DTV_MODULATION, object->modulation);
break;
case SYS_ISDBT:
if (object->isdbt_partial_reception == 1 &&
object->isdbt_layera_segment_count != 1) {
GST_WARNING_OBJECT (object, "Wrong ISDB-T parameter combination: "
"partial reception is set but layer A segment count is not 1");
}
if (!object->isdbt_sound_broadcasting) {
GST_INFO_OBJECT (object, "ISDB-T sound broadcasting is not set. "
"Driver will likely ignore values set for isdbt-sb-subchannel-id, "
"isdbt-sb-segment-idx and isdbt-sb-segment-count");
}
if (object->isdbt_layerc_modulation == DQPSK &&
object->isdbt_layerb_modulation != DQPSK) {
GST_WARNING_OBJECT (object, "Wrong ISDB-T parameter combination: "
"layer C modulation is DQPSK but layer B modulation is different");
}
if (object->bandwidth != 6000000) {
GST_WARNING_OBJECT (object, "Wrong ISDB-T parameter value: bandwidth "
"is %d but only 6 MHz is allowed", object->bandwidth);
}
GST_INFO_OBJECT (object, "Tuning ISDB-T to %d", freq);
set_prop (props->props, &n, DTV_BANDWIDTH_HZ, object->bandwidth);
set_prop (props->props, &n, DTV_GUARD_INTERVAL, object->guard_interval);
set_prop (props->props, &n, DTV_TRANSMISSION_MODE,
object->transmission_mode);
set_prop (props->props, &n, DTV_ISDBT_LAYER_ENABLED,
object->isdbt_layer_enabled);
set_prop (props->props, &n, DTV_ISDBT_PARTIAL_RECEPTION,
object->isdbt_partial_reception);
set_prop (props->props, &n, DTV_ISDBT_SOUND_BROADCASTING,
object->isdbt_sound_broadcasting);
set_prop (props->props, &n, DTV_ISDBT_SB_SUBCHANNEL_ID,
object->isdbt_sb_subchannel_id);
set_prop (props->props, &n, DTV_ISDBT_SB_SEGMENT_IDX,
object->isdbt_sb_segment_idx);
set_prop (props->props, &n, DTV_ISDBT_SB_SEGMENT_COUNT,
object->isdbt_sb_segment_count);
set_prop (props->props, &n, DTV_ISDBT_LAYERA_FEC,
object->isdbt_layera_fec);
set_prop (props->props, &n, DTV_ISDBT_LAYERA_MODULATION,
object->isdbt_layera_modulation);
set_prop (props->props, &n, DTV_ISDBT_LAYERA_SEGMENT_COUNT,
object->isdbt_layera_segment_count);
set_prop (props->props, &n, DTV_ISDBT_LAYERA_TIME_INTERLEAVING,
object->isdbt_layera_time_interleaving);
set_prop (props->props, &n, DTV_ISDBT_LAYERB_FEC,
object->isdbt_layerb_fec);
set_prop (props->props, &n, DTV_ISDBT_LAYERB_MODULATION,
object->isdbt_layerb_modulation);
set_prop (props->props, &n, DTV_ISDBT_LAYERB_SEGMENT_COUNT,
object->isdbt_layerb_segment_count);
set_prop (props->props, &n, DTV_ISDBT_LAYERB_TIME_INTERLEAVING,
object->isdbt_layerb_time_interleaving);
set_prop (props->props, &n, DTV_ISDBT_LAYERC_FEC,
object->isdbt_layerc_fec);
set_prop (props->props, &n, DTV_ISDBT_LAYERC_MODULATION,
object->isdbt_layerc_modulation);
set_prop (props->props, &n, DTV_ISDBT_LAYERC_SEGMENT_COUNT,
object->isdbt_layerc_segment_count);
set_prop (props->props, &n, DTV_ISDBT_LAYERC_TIME_INTERLEAVING,
object->isdbt_layerc_time_interleaving);
break;
#if HAVE_V5_MINOR(7)
case SYS_DTMB:
set_prop (props->props, &n, DTV_BANDWIDTH_HZ, object->bandwidth);
set_prop (props->props, &n, DTV_MODULATION, object->modulation);
set_prop (props->props, &n, DTV_INVERSION, object->inversion);
set_prop (props->props, &n, DTV_INNER_FEC, object->code_rate_hp);
set_prop (props->props, &n, DTV_TRANSMISSION_MODE,
object->transmission_mode);
set_prop (props->props, &n, DTV_GUARD_INTERVAL, object->guard_interval);
set_prop (props->props, &n, DTV_INTERLEAVING, object->interleaving);
/* FIXME: Make the LNA on/off switch a property and proxy on dvbbasebin */
/* FIXME: According to v4l advice (see libdvbv5 implementation) this
* property should be set separately as not all drivers will ignore it
* if unsupported. An alternative would be to get the dvb API contract
* revised on this regard */
set_prop (props->props, &n, DTV_LNA, LNA_AUTO);
GST_INFO_OBJECT (object, "Tuning DTMB to %d Hz", freq);
break;
#endif
default:
GST_ERROR_OBJECT (object, "Unknown frontend type %u", object->delsys);
return FALSE;
}
if (!gst_dvbsrc_is_valid_modulation (object->delsys, object->modulation)) {
GST_WARNING_OBJECT (object,
"Attempting an invalid modulation/delsys combination");
}
set_prop (props->props, &n, DTV_TUNE, 0);
props->num = n;
/* set first three entries */
n = 0;
set_prop (props->props, &n, DTV_DELIVERY_SYSTEM, object->delsys);
set_prop (props->props, &n, DTV_FREQUENCY, freq);
set_prop (props->props, &n, DTV_INVERSION, inversion);
return TRUE;
}
static gboolean
gst_dvbsrc_tune (GstDvbSrc * object)
{
/* found in mail archive on linuxtv.org
* What works well for us is:
* - first establish a TS feed (i.e. tune the frontend and check for success)
* - then set filters (PES/sections)
* - then tell the MPEG decoder to start
* - before tuning: first stop the MPEG decoder, then stop all filters
*/
if (!gst_dvbsrc_tune_fe (object)) {
GST_WARNING_OBJECT (object, "Unable to tune frontend");
return FALSE;
}
gst_dvbsrc_set_pes_filters (object);
return TRUE;
}
static void
gst_dvbsrc_unset_pes_filters (GstDvbSrc * object)
{
int i = 0;
GST_INFO_OBJECT (object, "clearing PES filter");
for (i = 0; i < MAX_FILTERS; i++) {
if (object->fd_filters[i] == -1)
continue;
close (object->fd_filters[i]);
object->fd_filters[i] = -1;
}
}
static void
gst_dvbsrc_set_pes_filters (GstDvbSrc * object)
{
int *fd;
int pid, i;
struct dmx_pes_filter_params pes_filter;
gint err;
gchar *demux_dev = g_strdup_printf ("/dev/dvb/adapter%d/demux%d",
object->adapter_number, object->frontend_number);
GST_INFO_OBJECT (object, "Setting PES filter");
for (i = 0; i < MAX_FILTERS; i++) {
if (object->pids[i] == G_MAXUINT16)
break;
fd = &object->fd_filters[i];
pid = object->pids[i];
if (*fd >= 0)
close (*fd);
if ((*fd = open (demux_dev, O_RDWR)) < 0) {
GST_ERROR_OBJECT (object, "Error opening demuxer: %s (%s)",
g_strerror (errno), demux_dev);
continue;
}
g_return_if_fail (*fd != -1);
pes_filter.pid = pid;
pes_filter.input = DMX_IN_FRONTEND;
pes_filter.output = DMX_OUT_TS_TAP;
pes_filter.pes_type = DMX_PES_OTHER;
pes_filter.flags = DMX_IMMEDIATE_START;
GST_INFO_OBJECT (object, "Setting pes-filter, pid = %d, type = %d",
pes_filter.pid, pes_filter.pes_type);
LOOP_WHILE_EINTR (err, ioctl (*fd, DMX_SET_PES_FILTER, &pes_filter));
if (err)
GST_WARNING_OBJECT (object, "Error setting PES filter on %s: %s",
demux_dev, g_strerror (errno));
}
g_free (demux_dev);
}