dvbv5-zap.c
/*
* Copyright (c) 2011-2012 - Mauro Carvalho Chehab
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation version 2
* of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Based on dvb-apps tzap utility, made by:
* Bernard Hatt 24/2/04
*/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE 1
#define _LARGEFILE64_SOURCE 1
/*
* Use a buffer big enough at least 1 second of data. It is interesting
* To have it multiple of a page. So, define it as a multiply of
* 4096.
*/
#define DVB_BUF_SIZE (4096 * 8 * 188)
/*
* Size of the buffer on read operations. The better is if it is
* smaller than DVB_BUF_SIZE, as we want to give more time for
* write() syscalls to be able to flush data.
*/
#define BUFLEN (188 * 512)
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <argp.h>
#include <sys/time.h>
#include <time.h>
#ifdef ENABLE_NLS
# define _(string) gettext(string)
# include "gettext.h"
# include <locale.h>
# include <langinfo.h>
# include <iconv.h>
#else
# define _(string) string
#endif
# define N_(string) string
#include <linux/dvb/dmx.h>
#include "libdvbv5/dvb-file.h"
#include "libdvbv5/dvb-demux.h"
#include "libdvbv5/dvb-dev.h"
#include "libdvbv5/dvb-scan.h"
#include "libdvbv5/header.h"
#include "libdvbv5/countries.h"
#define CHANNEL_FILE "channels.conf"
#define PROGRAM_NAME "dvbv5-zap"
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
const int NANO_SECONDS_IN_SEC = 1000000000;
const char *argp_program_version = PROGRAM_NAME " version " V4L_UTILS_VERSION;
const char *argp_program_bug_address = "Mauro Carvalho Chehab <mchehab@kernel.org>";
struct arguments {
char *confname, *lnb_name, *output, *demux_dev, *dvr_dev, *dvr_fname;
char *filename, *dvr_pipe;
unsigned adapter, frontend, demux, get_detected, get_nit;
int lna, lnb, sat_number;
unsigned diseqc_wait, silent, verbose, frontend_only, freq_bpf;
unsigned timeout, dvr, rec_psi, exit_after_tuning;
unsigned n_apid, n_vpid, extra_pids, all_pids;
enum dvb_file_formats input_format, output_format;
unsigned traffic_monitor, low_traffic, non_human, port;
char *search, *server;
const char *cc;
/* Used by status print */
unsigned n_status_lines;
};
static const struct argp_option options[] = {
{"adapter", 'a', N_("adapter#"), 0, N_("use given adapter (default 0)"), 0},
{"audio_pid", 'A', N_("audio_pid#"), 0, N_("audio pid program to use (default 0)"), 0},
{"channels", 'c', N_("file"), 0, N_("read channels list from 'file'"), 0},
{"extra-pids", 'E', NULL, 0, N_("output all channel pids"), 0 },
{"demux", 'd', N_("demux#"), 0, N_("use given demux (default 0)"), 0},
{"frontend", 'f', N_("frontend#"), 0, N_("use given frontend (default 0)"), 0},
{"input-format", 'I', N_("format"), 0, N_("Input format: ZAP, CHANNEL, DVBV5 (default: DVBV5)"), 0},
{"lna", 'w', N_("LNA (0, 1, -1)"), 0, N_("enable/disable/auto LNA power"), 0},
{"lnbf", 'l', N_("LNBf_type"), 0, N_("type of LNBf to use. 'help' lists the available ones"), 0},
{"search", 'L', N_("string"), 0, N_("search/look for a string inside the traffic"), 0},
{"monitor", 'm', NULL, 0, N_("monitors the DVB traffic"), 0},
{"output", 'o', N_("file"), 0, N_("output filename (use -o - for stdout)"), 0},
{"pat", 'p', NULL, 0, N_("add pat and pmt to TS recording (implies -r)"), 0},
{"all-pids", 'P', NULL, 0, N_("don't filter any pids. Instead, outputs all of them"), 0 },
{"record", 'r', NULL, 0, N_("set up /dev/dvb/adapterX/dvr0 for TS recording"), 0},
{"silence", 's', NULL, 0, N_("increases silence (can be used more than once)"), 0},
{"sat_number", 'S', N_("satellite_number"), 0, N_("satellite number. If not specified, disable DISEqC"), 0},
{"timeout", 't', N_("seconds"), 0, N_("timeout for zapping and for recording"), 0},
{"freq_bpf", 'U', N_("frequency"), 0, N_("SCR/Unicable band-pass filter frequency to use, in kHz"), 0},
{"verbose", 'v', NULL, 0, N_("verbose debug messages (can be used more than once)"), 0},
{"video_pid", 'V', N_("video_pid#"), 0, N_("video pid program to use (default 0)"), 0},
{"wait", 'W', N_("time"), 0, N_("adds additional wait time for DISEqC command completion"), 0},
{"exit", 'x', NULL, 0, N_("exit after tuning"), 0},
{"low_traffic", 'X', N_("packets_per_sec"), 0, N_("sets DVB low traffic threshold. PIDs with less than this amount of packets per second will be ignored. Default: 1 packet per second"), 0},
{"cc", 'C', N_("country_code"), 0, N_("Set the default country to be used (in ISO 3166-1 two letter code)"), 0},
{"non-numan", 'N', NULL, 0, N_("Non-human formatted stats (useful for scripts)"), 0},
{"server", 'H', N_("SERVER"), 0, N_("dvbv5-daemon host IP address"), 0},
{"tcp-port", 'T', N_("PORT"), 0, N_("dvbv5-daemon host tcp port"), 0},
{"dvr-pipe", 'D', N_("PIPE"), 0, N_("Named pipe for DVR output, when using remote access (by default: /tmp/dvr-pipe)"), 0},
{"help", '?', 0, 0, N_("Give this help list"), -1},
{"usage", -3, 0, 0, N_("Give a short usage message")},
{"version", -4, 0, 0, N_("Print program version"), -1},
{ 0, 0, 0, 0, 0, 0 }
};
static int timeout_flag = 0;
#define ERROR(x...) \
do { \
fprintf(stderr, _("ERROR: ")); \
fprintf(stderr, x); \
fprintf(stderr, "\n"); \
} while (0)
#define PERROR(x...) \
do { \
fprintf(stderr, _("ERROR: ")); \
fprintf(stderr, x); \
fprintf(stderr, " (%s)\n", strerror(errno)); \
} while (0)
#define monitor_log(msg, args...) \
do { \
struct timespec __now = { 0 }; \
float __diff; \
\
clock_gettime(CLOCK_MONOTONIC, &__now); \
__diff = __now.tv_sec * 1. \
+ __now.tv_nsec *1. / NANO_SECONDS_IN_SEC; \
fprintf(stderr, msg, __diff, ##args); \
} while (0)
/*
* Find channel configuration.
* On success, the caller must dvb_file_free(*out_file).
*/
static int parse(struct arguments *args,
struct dvb_v5_fe_parms *parms,
const char *channel,
struct dvb_file **out_file,
const struct dvb_entry **out_entry)
{
struct dvb_file *dvb_file;
struct dvb_entry *entry;
int i;
uint32_t sys;
*out_file = NULL;
*out_entry = NULL;
/* This is used only when reading old formats */
switch (parms->current_sys) {
case SYS_DVBT:
case SYS_DVBS:
case SYS_DVBC_ANNEX_A:
case SYS_ATSC:
sys = parms->current_sys;
break;
case SYS_DVBC_ANNEX_C:
sys = SYS_DVBC_ANNEX_A;
break;
case SYS_DVBC_ANNEX_B:
sys = SYS_ATSC;
break;
case SYS_ISDBT:
case SYS_DTMB:
sys = SYS_DVBT;
break;
default:
sys = SYS_UNDEFINED;
break;
}
dvb_file = dvb_read_file_format(args->confname, sys,
args->input_format);
if (!dvb_file)
return -2;
for (entry = dvb_file->first_entry; entry != NULL; entry = entry->next) {
if (entry->channel && !strcmp(entry->channel, channel))
break;
if (entry->vchannel && !strcmp(entry->vchannel, channel))
break;
}
/*
* Give a second shot, using a case insensitive seek
*/
if (!entry) {
for (entry = dvb_file->first_entry; entry != NULL;
entry = entry->next) {
if (entry->channel && !strcasecmp(entry->channel, channel))
break;
}
}
/*
* When this tool is used to just tune to a channel, to monitor it or
* to capture all PIDs, all it needs is a frequency.
* So, let the tool to accept a frequency as the tuning channel on those
* cases.
* This way, a file in "channel" format can be used instead of a zap file.
* It is also easier to use it for testing purposes.
*/
if (!entry && (!args->dvr && !args->rec_psi)) {
uint32_t f, freq = atoi(channel);
if (freq) {
for (entry = dvb_file->first_entry; entry != NULL;
entry = entry->next) {
dvb_retrieve_entry_prop(entry, DTV_FREQUENCY, &f);
if (f == freq)
break;
}
}
}
if (!entry) {
ERROR("Can't find channel");
dvb_file_free(dvb_file);
return -3;
}
/*
* Both the DVBv5 format and the command line parameters may
* specify the LNBf. If both have the definition, use the one
* provided by the command line parameter, overriding the one
* stored in the channel file.
*/
if (entry->lnb && !parms->lnb) {
int lnb = dvb_sat_search_lnb(entry->lnb);
if (lnb == -1) {
ERROR("unknown LNB %s\n", entry->lnb);
dvb_file_free(dvb_file);
return -1;
}
parms->lnb = dvb_sat_get_lnb(lnb);
}
if (parms->sat_number < 0 && entry->sat_number >= 0)
parms->sat_number = entry->sat_number;
if (entry->other_el_pid) {
int i, type = -1;
for (i = 0; i < entry->other_el_pid_len; i++) {
if (type != entry->other_el_pid[i].type) {
type = entry->other_el_pid[i].type;
if (i)
fprintf(stderr, "\n");
fprintf(stderr, _("service has pid type %02x: "), type);
}
fprintf(stderr, " %d", entry->other_el_pid[i].pid);
}
fprintf(stderr, "\n");
}
/* First of all, set the delivery system */
dvb_retrieve_entry_prop(entry, DTV_DELIVERY_SYSTEM, &sys);
dvb_set_compat_delivery_system(parms, sys);
/* Copy data into parms */
for (i = 0; i < entry->n_props; i++) {
uint32_t data = entry->props[i].u.data;
/* Don't change the delivery system */
if (entry->props[i].cmd == DTV_DELIVERY_SYSTEM)
continue;
dvb_fe_store_parm(parms, entry->props[i].cmd, data);
if (parms->current_sys == SYS_ISDBT) {
dvb_fe_store_parm(parms, DTV_ISDBT_PARTIAL_RECEPTION, 0);
dvb_fe_store_parm(parms, DTV_ISDBT_SOUND_BROADCASTING, 0);
dvb_fe_store_parm(parms, DTV_ISDBT_LAYER_ENABLED, 0x07);
if (entry->props[i].cmd == DTV_CODE_RATE_HP) {
dvb_fe_store_parm(parms, DTV_ISDBT_LAYERA_FEC,
data);
dvb_fe_store_parm(parms, DTV_ISDBT_LAYERB_FEC,
data);
dvb_fe_store_parm(parms, DTV_ISDBT_LAYERC_FEC,
data);
} else if (entry->props[i].cmd == DTV_MODULATION) {
dvb_fe_store_parm(parms,
DTV_ISDBT_LAYERA_MODULATION,
data);
dvb_fe_store_parm(parms,
DTV_ISDBT_LAYERB_MODULATION,
data);
dvb_fe_store_parm(parms,
DTV_ISDBT_LAYERC_MODULATION,
data);
}
}
if (parms->current_sys == SYS_ATSC &&
entry->props[i].cmd == DTV_MODULATION) {
if (data != VSB_8 && data != VSB_16)
dvb_fe_store_parm(parms,
DTV_DELIVERY_SYSTEM,
SYS_DVBC_ANNEX_B);
}
}
*out_file = dvb_file;
*out_entry = entry;
return 0;
}
static int setup_frontend(struct arguments *args,
struct dvb_v5_fe_parms *parms)
{
int rc;
uint32_t freq;
if (args->silent < 2) {
rc = dvb_fe_retrieve_parm(parms, DTV_FREQUENCY, &freq);
if (rc < 0) {
ERROR("can't get the frequency");
return -1;
}
fprintf(stderr, _("tuning to %i Hz\n"), freq);
}
rc = dvb_fe_set_parms(parms);
if (rc < 0) {
ERROR("dvb_fe_set_parms failed");
return -1;
}
return 0;
}
static void do_timeout(int x)
{
(void)x;
if (timeout_flag == 0) {
timeout_flag = 1;
alarm(2);
signal(SIGALRM, do_timeout);
} else {
/* something has gone wrong ... exit */
fprintf(stderr, "Forcing program stop due to timeout or terminate signal\n");
exit(1);
}
}
static int print_non_human_stats(FILE *fd, struct dvb_v5_fe_parms *parms)
{
int rc;
fe_status_t status;
uint32_t snr = 0, _signal = 0, quality = 0;
uint32_t ber = 0, per = 0, pre_ber = 0, uncorrected_blocks = 0;
rc = dvb_fe_get_stats(parms);
if (rc < 0) {
PERROR("dvb_fe_get_stats failed");
return -1;
}
dvb_fe_retrieve_stats(parms, DTV_STATUS, &status);
dvb_fe_retrieve_stats(parms, DTV_QUALITY, &quality);
dvb_fe_retrieve_stats(parms, DTV_STAT_SIGNAL_STRENGTH, &_signal);
dvb_fe_retrieve_stats(parms, DTV_STAT_CNR, &snr);
dvb_fe_retrieve_stats(parms, DTV_BER, &ber);
dvb_fe_retrieve_stats(parms, DTV_STAT_ERROR_BLOCK_COUNT, &uncorrected_blocks);
dvb_fe_retrieve_stats(parms, DTV_PRE_BER, &pre_ber);
dvb_fe_retrieve_stats(parms, DTV_PER, &per);
fprintf(fd,"status %02x | quality %02x | signal %04x | snr %04x | ber %08x | unc %08x | pre_ber %08x | per %08x | ",
status, quality, _signal, snr, ber, uncorrected_blocks, pre_ber, per);
if (status & FE_HAS_LOCK)
fprintf(fd, "FE_HAS_LOCK");
fprintf(fd, "\n");
fflush(fd);
return 0;
}
static int print_frontend_stats(FILE *fd,
struct arguments *args,
struct dvb_v5_fe_parms *parms)
{
char buf[512], *p;
int rc, i, len, show;
uint32_t status = 0;
if (args->non_human)
return print_non_human_stats(fd, parms);
/* Move cursor up and cleans down */
if (isatty(fileno(fd)) && args->n_status_lines)
fprintf(fd, "\r\x1b[%dA\x1b[J", args->n_status_lines);
args->n_status_lines = 0;
rc = dvb_fe_get_stats(parms);
if (rc) {
ERROR("dvb_fe_get_stats failed");
return -1;
}
p = buf;
len = sizeof(buf);
dvb_fe_snprintf_stat(parms, DTV_STATUS, NULL, 0, &p, &len, &show);
for (i = 0; i < MAX_DTV_STATS; i++) {
show = 1;
dvb_fe_snprintf_stat(parms, DTV_QUALITY, _("Quality"),
i, &p, &len, &show);
dvb_fe_snprintf_stat(parms, DTV_STAT_SIGNAL_STRENGTH, _("Signal"),
i, &p, &len, &show);
dvb_fe_snprintf_stat(parms, DTV_STAT_CNR, _("C/N"),
i, &p, &len, &show);
dvb_fe_snprintf_stat(parms, DTV_STAT_ERROR_BLOCK_COUNT, _("UCB"),
i, &p, &len, &show);
dvb_fe_snprintf_stat(parms, DTV_BER, _("postBER"),
i, &p, &len, &show);
dvb_fe_snprintf_stat(parms, DTV_PRE_BER, _("preBER"),
i, &p, &len, &show);
dvb_fe_snprintf_stat(parms, DTV_PER, _("PER"),
i, &p, &len, &show);
if (p != buf) {
if (args->n_status_lines)
fprintf(fd, "\t%s\n", buf);
else
fprintf(fd, "%s\n", buf);
args->n_status_lines++;
p = buf;
len = sizeof(buf);
}
}
fflush(fd);
/* While not lock, display status on a new line */
dvb_fe_retrieve_stats(parms, DTV_STATUS, &status);
if (!isatty(fileno(fd)) || !(status & FE_HAS_LOCK))
fprintf(fd, "\n");
return 0;
}
static int check_frontend(struct arguments *args,
struct dvb_v5_fe_parms *parms)
{
int rc;
fe_status_t status = 0;
do {
rc = dvb_fe_get_stats(parms);
if (rc) {
ERROR("dvb_fe_get_stats failed");
usleep(1000000);
continue;
}
status = 0;
rc = dvb_fe_retrieve_stats(parms, DTV_STATUS, &status);
if (rc) {
ERROR("dvb_fe_retrieve_stats failed");
usleep(1000000);
continue;
}
if (!args->silent)
print_frontend_stats(stderr, args, parms);
if (status & FE_HAS_LOCK)
break;
usleep(1000000);
} while (!timeout_flag);
if (args->silent < 2)
print_frontend_stats(stderr, args, parms);
return status & FE_HAS_LOCK;
}
static void get_show_stats(FILE *fp, struct arguments *args,
struct dvb_v5_fe_parms *parms,
int loop)
{
int rc;
args->n_status_lines = 0;
do {
rc = dvb_fe_get_stats(parms);
if (!rc)
print_frontend_stats(fp, args, parms);
if (!timeout_flag && loop)
usleep(1000000);
} while (!timeout_flag && loop);
}
static struct timespec *elapsed_time(struct timespec *start)
{
static struct timespec elapsed;
struct timespec end;
if (!start->tv_sec && !start->tv_nsec)
return NULL;
if (clock_gettime(CLOCK_MONOTONIC, &end))
return NULL;
elapsed.tv_sec = end.tv_sec - start->tv_sec;
elapsed.tv_nsec = end.tv_nsec - start->tv_nsec;
if (elapsed.tv_nsec < 0) {
elapsed.tv_sec--;
elapsed.tv_nsec += NANO_SECONDS_IN_SEC;
}
return &elapsed;
}
static void copy_to_file(struct dvb_open_descriptor *in_fd, int out_fd,
int timeout, int silent)
{
char buf[BUFLEN];
int r, first = 1;
long long int rc = 0LL;
struct timespec start, *elapsed;
/* Initialize start time, due to -EOVERFLOW with first == 1 */
clock_gettime(CLOCK_MONOTONIC, &start);
while (timeout_flag == 0) {
r = dvb_dev_read(in_fd, buf, sizeof(buf));
if (r < 0) {
if (r == -EOVERFLOW) {
elapsed = elapsed_time(&start);
if (!elapsed)
fprintf(stderr, _("buffer overrun at %lld\n"), rc);
else
fprintf(stderr, _("buffer overrun after %lld.%02ld seconds\n"),
(long long)elapsed->tv_sec,
elapsed->tv_nsec / 10000000);
continue;
}
ERROR("Read failed");
break;
}
/*
* It takes a while for a DVB device to start streaming, as the
* hardware may be waiting for some locks. The safest way to
* ensure that a program record will have the start amount of
* time specified by the user is to restart the timeout alarm
* here, after the first succeded read.
*
* So, let's reset the start time here.
*/
if (first) {
if (timeout > 0)
alarm(timeout);
clock_gettime(CLOCK_MONOTONIC, &start);
first = 0;
}
if (write(out_fd, buf, r) < 0) {
PERROR(_("Write failed"));
break;
}
rc += r;
}
if (silent < 2) {
if (timeout)
fprintf(stderr, _("received %lld bytes (%lld Kbytes/sec)\n"), rc,
rc / (1024 * timeout));
else
fprintf(stderr, _("received %lld bytes\n"), rc);
}
}
static error_t parse_opt(int k, char *optarg, struct argp_state *state)
{
struct arguments *args = state->input;
switch (k) {
case 'a':
args->adapter = strtoul(optarg, NULL, 0);
break;
case 'f':
args->frontend = strtoul(optarg, NULL, 0);
break;
case 'd':
args->demux = strtoul(optarg, NULL, 0);
break;
case 't':
args->timeout = strtoul(optarg, NULL, 0);
break;
case 'I':
args->input_format = dvb_parse_format(optarg);
break;
case 'o':
args->filename = strdup(optarg);
/* fall through */
case 'r':
args->dvr = 1;
break;
case 'p':
args->rec_psi = 1;
break;
case 'x':
args->exit_after_tuning = 1;
break;
case 'c':
args->confname = strdup(optarg);
break;
case 'w':
if (!strcasecmp(optarg,"on")) {
args->lna = 1;
} else if (!strcasecmp(optarg,"off")) {
args->lna = 0;
} else if (!strcasecmp(optarg,"auto")) {
args->lna = LNA_AUTO;
} else {
int val = strtoul(optarg, NULL, 0);
if (!val)
args->lna = 0;
else if (val > 0)
args->lna = 1;
else
args->lna = LNA_AUTO;
}
break;
case 'l':
args->lnb_name = strdup(optarg);
break;
case 'S':
args->sat_number = strtoul(optarg, NULL, 0);
break;
case 'U':
args->freq_bpf = strtoul(optarg, NULL, 0);
break;
case 'W':
args->diseqc_wait = strtoul(optarg, NULL, 0);
break;
case 's':
args->silent++;
break;
case 'v':
args->verbose++;
break;
case 'A':
args->n_apid = strtoul(optarg, NULL, 0);
break;
case 'V':
args->n_vpid = strtoul(optarg, NULL, 0);
break;
case 'E':
args->extra_pids = 1;
break;
case 'P':
args->all_pids = 1;
break;
case 'm':
args->traffic_monitor = 1;
break;
case 'N':
args->non_human = 1;
break;
case 'X':
args->low_traffic = atoi(optarg);
break;
case 'L':
args->search = strdup(optarg);
break;
case 'C':
args->cc = strndup(optarg, 2);
break;
case 'H':
args->server = strdup(optarg);
break;
case 'T':
args->port = atoi(optarg);
break;
case 'D':
args->dvr_pipe = strdup(optarg);
break;
case '?':
argp_state_help(state, state->out_stream,
ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG
| ARGP_HELP_DOC);
fprintf(state->out_stream, _("\nReport bugs to %s.\n"), argp_program_bug_address);
exit(0);
case -4:
fprintf (state->out_stream, "%s\n", argp_program_version);
exit(0);
case -3:
argp_state_help(state, state->out_stream, ARGP_HELP_USAGE);
exit(0);
default:
return ARGP_ERR_UNKNOWN;
};
return 0;
}
static char *print_bytes(float val)
{
static char buf[20];
char *prefix = "";
if (val >= 500 * 1024 * 1024) {
prefix = "G";
val /= 1024 * 1024 * 1024.;
} else if (val >= 500 * 1024) {
prefix = "M";
val /= 1024 * 1024.;
} else if (val >= 500) {
prefix = "K";
val /= 1024.;
}
if (*prefix) {
if (snprintf(buf, sizeof(buf), "%8.3f %s", val, prefix) <= 0)
return " NaN ";
} else {
if (snprintf(buf, sizeof(buf), "%9.3f ", val) <= 0)
return " NaN ";
}
return buf;
}
int do_traffic_monitor(struct arguments *args, struct dvb_device *dvb,
int out_fd, int timeout)
{
struct dvb_open_descriptor *fd, *dvr_fd;
struct timespec startt;
struct dvb_v5_fe_parms *parms = dvb->fe_parms;
unsigned long long pidt[0x2001], wait, cont_err = 0;
unsigned long long err_cnt[0x2000];
signed char pid_cont[0x2000];
int i, first = 1;
memset(pidt, 0, sizeof(pidt));
memset(err_cnt, 0, sizeof(err_cnt));
memset(pid_cont, 0, sizeof(pid_cont));
args->exit_after_tuning = 1;
check_frontend(args, parms);
dvr_fd = dvb_dev_open(dvb, args->dvr_dev, O_RDONLY);
if (!dvr_fd)
return -1;
fprintf(stderr, _("dvb_dev_set_bufsize: buffer set to %d\n"), DVB_BUF_SIZE);
dvb_dev_set_bufsize(dvr_fd, DVB_BUF_SIZE);
fd = dvb_dev_open(dvb, args->demux_dev, O_RDWR);
if (!fd) {
dvb_dev_close(dvr_fd);
return -1;
}
if (args->silent < 2)
fprintf(stderr, _(" dvb_set_pesfilter to 0x2000\n"));
if (dvb_dev_dmx_set_pesfilter(fd, 0x2000, DMX_PES_OTHER,
DMX_OUT_TS_TAP, 0) < 0) {
dvb_dev_close(dvr_fd);
dvb_dev_close(fd);
return -1;
}
if (clock_gettime(CLOCK_MONOTONIC, &startt)) {
fprintf(stderr, _("Can't get timespec\n"));
return -1;
}
wait = 1000;
monitor_log(_("%.2fs: Starting capture\n"));
while (1) {
struct timespec *elapsed;
unsigned char buffer[BUFLEN];
int pid, ok, diff;
ssize_t r;
if (timeout_flag)
break;
if ((r = dvb_dev_read(dvr_fd, buffer, BUFLEN)) <= 0) {
if (r == -EOVERFLOW) {
monitor_log(_("%.2fs: buffer overrun\n"));
continue;
}
monitor_log(_("%.2fs: read() returned error %zd\n"), r);
break;
}
/*
* It takes a while for a DVB device to start streaming, as the
* hardware may be waiting for some locks. The safest way to
* ensure that a program record will have the start amount of
* time specified by the user is to restart the timeout alarm
* here, after the first succeded read.
*/
if (first) {
if (timeout > 0)
alarm(timeout);
first = 0;
}
if (out_fd >= 0) {
if (write(out_fd, buffer, r) < 0) {
PERROR(_("Write failed"));
break;
}
}
if (r != BUFLEN) {
monitor_log(_("%.2fs: only read %zd bytes\n"), r);
break;
}
for (i = 0; i < BUFLEN; i += 188) {
struct dvb_ts_packet_header *h = (void *)&buffer[i];
if (h->sync_byte != 0x47) {
monitor_log(_("%.2fs: invalid sync byte. Discarding %zd bytes\n"), r);
continue;
}
bswap16(h->bitfield);
#if 0
/*
* ITU-T Rec. H.222.0 decoders shall discard Transport
* Stream packets with the adaptation_field_control
* field set to a value of '00' (invalid). Packets with
* a value of '01' are NULL packets. Yet, as those are
* actually part of the stream, we won't be discarding,
* as we want to take them into account for traffic
* estimation purposes.
*/
if (h->adaptation_field_control == 0)
continue;
#endif
ok = 1;
pid = h->pid;
if (pid > 0x1fff) {
monitor_log(_("%.2fs: invalid pid: 0x%04x\n"),
pid);
pid = 0x1fff;
}
/*
* After 1 second of processing, check if are there
* any issues with regards to frame continuity for
* non-NULL packets.
*
* According to ITU-T H.222.0 | ISO/IEC 13818-1, the
* continuity counter isn't incremented if the packet
* is 00 or 10. It is only incremented on odd values.
*
* Also, don't check continuity errors on the first
* second, as the frontend is still starting streaming
*/
if (pid < 0x1fff && h->adaptation_field_control & 1) {
int discontinued = 0;
if (h->adaptation_field_control & 2) {
if (h->adaptation_field_length >= 1) {
discontinued = h->discontinued;
} else {
monitor_log(_("%.2fs: pid %d has adaption layer, but size is too small!\n"),
pid);
}
}
if (wait < 2000)
discontinued = 1;
if (!discontinued && pid_cont[pid] >= 0) {
unsigned int next = (pid_cont[pid] + 1) % 16;
if (next != h->continuity_counter) {
monitor_log(_("%.2fs: pid %d, expecting %d received %d\n"),
pid, next,
h->continuity_counter);
discontinued = 1;
cont_err++;
err_cnt[pid]++;
}
}
if (discontinued)
pid_cont[pid] = -1;
else
pid_cont[pid] = h->continuity_counter;
}
if (args->search) {
int i, sl = strlen(args->search);
ok = 0;
if (pid != 0x1fff) {
for (i = 0; i < (188 - sl); ++i) {
if (!memcmp((char *)h + i, args->search, sl))
ok = 1;
}
}
}
if (ok) {
pidt[pid]++;
pidt[0x2000]++;
}
}
elapsed = elapsed_time(&startt);
if (!elapsed)
diff = wait;
else
diff = (unsigned long long)elapsed->tv_sec * 1000
+ elapsed->tv_nsec * 1000 / NANO_SECONDS_IN_SEC;
if (diff > wait) {
unsigned long long other_pidt = 0, other_err_cnt = 0;
if (isatty(STDOUT_FILENO))
printf("\x1b[1H\x1b[2J");
args->n_status_lines = 0;
printf(_(" PID FREQ SPEED TOTAL\n"));
int _pid = 0;
for (_pid = 0; _pid < 0x2000; _pid++) {
if (pidt[_pid]) {
if (args->low_traffic && (pidt[_pid] * 1000. / diff) < args->low_traffic) {
other_pidt += pidt[_pid];
other_err_cnt += err_cnt[_pid];
continue;
}
printf("%5d %9.2f p/s %sbps ",
_pid,
pidt[_pid] * 1000. / diff,
print_bytes(pidt[_pid] * 1000. * 8 * 188/ diff));
if (pidt[_pid] * 188 / 1024)
printf("%8llu KB", (pidt[_pid] * 188 + 512) / 1024);
else
printf(" %8llu B", pidt[_pid] * 188);
if (err_cnt[_pid] > 0)
printf(" %8llu continuity errors",
err_cnt[_pid]);
printf("\n");
}
}
if (other_pidt) {
printf(_("OTHER"));
printf(" %9.2f p/s %sbps ",
other_pidt * 1000. / diff,
print_bytes(other_pidt * 1000. * 8 * 188/ diff));
if (other_pidt * 188 / 1024)
printf("%8llu KB", (other_pidt * 188 + 512) / 1024);
else
printf(" %8llu B", other_pidt * 188);
if (other_err_cnt > 0)
printf(" %8llu continuity errors",
other_err_cnt);
printf("\n");
}
/* 0x2000 is the total traffic */
printf("TOT %11.2f p/s %sbps %8llu KB\n",
pidt[_pid] * 1000. / diff,
print_bytes(pidt[_pid] * 1000. * 8 * 188/ diff),
(pidt[_pid] * 188 + 512) / 1024);
printf("\n");
get_show_stats(stdout, args, parms, 0);
wait += 1000;
if (cont_err)
printf("CONTINUITY errors: %llu\n", cont_err);
}
}
monitor_log(_("%.2fs: Stopping capture\n"));
dvb_dev_close(dvr_fd);
dvb_dev_close(fd);
return 0;
}
static void set_signals(struct arguments *args)
{
signal(SIGTERM, do_timeout);
signal(SIGINT, do_timeout);
if (args->timeout > 0) {
signal(SIGALRM, do_timeout);
alarm(args->timeout);
}
}
static char *default_dvr_pipe = "/tmp/dvr-pipe";
int main(int argc, char **argv)
{
struct arguments args = {};
char *homedir = getenv("HOME");
char *channel = NULL;
int lnb = -1, idx = -1;
int pmtpid = 0;
struct dvb_file *dvb_file = NULL;
const struct dvb_entry *dvb_entry = NULL;
struct dvb_open_descriptor *pat_fd = NULL, *pmt_fd = NULL;
struct dvb_open_descriptor *sdt_fd = NULL;
struct dvb_open_descriptor *sid_fd = NULL, *dvr_fd = NULL;
int file_fd = -1;
int err = -1;
int r, ret;
struct dvb_v5_fe_parms *parms = NULL;
struct dvb_device *dvb;
struct dvb_dev_list *dvb_dev;
const struct argp argp = {
.options = options,
.parser = parse_opt,
.doc = N_("DVB zap utility"),
.args_doc = N_("<channel name> [or <frequency> if in monitor mode]"),
};
#ifdef ENABLE_NLS
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
#endif
args.sat_number = -1;
args.lna = LNA_AUTO;
args.input_format = FILE_DVBV5;
args.dvr_pipe = default_dvr_pipe;
args.low_traffic = 1;
if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, &idx, &args)) {
argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME);
return -1;
}
if (idx < argc)
channel = argv[idx];
if (!channel) {
argp_help(&argp, stderr, ARGP_HELP_STD_HELP, PROGRAM_NAME);
return -1;
}
if (args.input_format == FILE_UNKNOWN) {
ERROR("Please specify a valid format\n");
argp_help(&argp, stderr, ARGP_HELP_STD_HELP, PROGRAM_NAME);
return -1;
}
if (!args.traffic_monitor && args.search) {
ERROR("search string can be used only on monitor mode\n");
argp_help(&argp, stderr, ARGP_HELP_STD_HELP, PROGRAM_NAME);
return -1;
}
if (args.lnb_name) {
lnb = dvb_sat_search_lnb(args.lnb_name);
if (lnb < 0) {
printf(_("Please select one of the LNBf's below:\n"));
dvb_print_all_lnb();
exit(1);
} else {
printf(_("Using LNBf "));
dvb_print_lnb(lnb);
}
}
dvb = dvb_dev_alloc();
if (!dvb)
return -1;
if (args.server && args.port) {
printf(_("Connecting to %s:%d\n"), args.server, args.port);
ret = dvb_dev_remote_init(dvb, args.server, args.port);
if (ret < 0)
return -1;
}
dvb_dev_set_log(dvb, args.verbose, NULL);
dvb_dev_find(dvb, NULL, NULL);
parms = dvb->fe_parms;
dvb_dev = dvb_dev_seek_by_adapter(dvb, args.adapter, args.demux, DVB_DEVICE_DEMUX);
if (!dvb_dev) {
fprintf(stderr, _("Couldn't find demux device node\n"));
dvb_dev_free(dvb);
return -1;
}
args.demux_dev = dvb_dev->sysname;
dvb_dev = dvb_dev_seek_by_adapter(dvb, args.adapter, args.demux, DVB_DEVICE_DVR);
if (!dvb_dev) {
fprintf(stderr, _("Couldn't find dvr device node\n"));
dvb_dev_free(dvb);
return -1;
}
args.dvr_dev = dvb_dev->sysname;
args.dvr_fname = dvb_dev->path;
if (args.silent < 2)
fprintf(stderr, _("using demux '%s'\n"), args.demux_dev);
if (!args.confname) {
if (!homedir)
ERROR("$HOME not set");
r = asprintf(&args.confname, "%s/.tzap/%i/%s",
homedir, args.adapter, CHANNEL_FILE);
if (access(args.confname, R_OK)) {
free(args.confname);
r = asprintf(&args.confname, "%s/.tzap/%s",
homedir, CHANNEL_FILE);
}
}
fprintf(stderr, _("reading channels from file '%s'\n"), args.confname);
dvb_dev = dvb_dev_seek_by_adapter(dvb, args.adapter, args.frontend,
DVB_DEVICE_FRONTEND);
if (!dvb_dev)
return -1;
if (!dvb_dev_open(dvb, dvb_dev->sysname, O_RDWR))
goto err;
if (lnb >= 0)
parms->lnb = dvb_sat_get_lnb(lnb);
if (args.sat_number >= 0)
parms->sat_number = args.sat_number;
parms->diseqc_wait = args.diseqc_wait;
parms->freq_bpf = args.freq_bpf;
parms->lna = args.lna;
r = dvb_fe_set_default_country(parms, args.cc);
if (r < 0)
fprintf(stderr, _("Failed to set the country code:%s\n"), args.cc);
if (parse(&args, parms, channel, &dvb_file, &dvb_entry))
goto err;
if (setup_frontend(&args, parms) < 0)
goto err;
if (args.exit_after_tuning) {
set_signals(&args);
err = 0;
check_frontend(&args, parms);
goto err;
}
if (args.traffic_monitor) {
if (args.filename) {
file_fd = open(args.filename,
O_LARGEFILE |
O_WRONLY | O_CREAT | O_TRUNC,
0644);
if (file_fd < 0) {
PERROR(_("open of '%s' failed"), args.filename);
return -1;
}
}
set_signals(&args);
err = do_traffic_monitor(&args, dvb, file_fd, args.timeout);
goto err;
}
if (args.rec_psi) {
sid_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!sid_fd) {
ERROR("opening sid demux failed");
return -1;
}
pmtpid = dvb_dev_dmx_get_pmt_pid(sid_fd, dvb_entry->service_id);
dvb_dev_close(sid_fd);
if (pmtpid <= 0) {
fprintf(stderr, _("couldn't find pmt-pid for sid %04x\n"),
dvb_entry->service_id);
goto err;
}
pat_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!pat_fd) {
ERROR("opening pat demux failed");
goto err;
}
if (dvb_dev_dmx_set_pesfilter(pat_fd, 0, DMX_PES_OTHER,
args.dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER,
args.dvr ? 64 * 1024 : 0) < 0)
goto err;
pmt_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!pmt_fd) {
ERROR("opening pmt demux failed");
goto err;
}
if (dvb_dev_dmx_set_pesfilter(pmt_fd, pmtpid, DMX_PES_OTHER,
args.dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER,
args.dvr ? 64 * 1024 : 0) < 0)
goto err;
/*
* SDT may also be needed in order to play some streams
*/
sdt_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!sdt_fd) {
ERROR("opening sdt demux failed");
goto err;
}
if (dvb_dev_dmx_set_pesfilter(sdt_fd, 0x0011, DMX_PES_OTHER,
args.dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER,
args.dvr ? 64 * 1024 : 0) < 0)
goto err;
}
if (args.all_pids) {
struct dvb_open_descriptor *video_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!video_fd) {
ERROR("failed opening '%s'", args.demux_dev);
goto err;
}
fprintf(stderr, _("dvb_dev_set_bufsize: buffer set to %d\n"), DVB_BUF_SIZE);
dvb_dev_set_bufsize(video_fd, DVB_BUF_SIZE);
if (args.silent < 2) {
fprintf(stderr, _("pass all PIDs to TS\n"));
fprintf(stderr, _(" dvb_set_pesfilter %d\n"), 0x2000);
}
if (dvb_dev_dmx_set_pesfilter(video_fd, 0x2000, DMX_PES_OTHER,
DMX_OUT_TS_TAP, 0) < 0) {
goto err;
}
} else {
if (dvb_entry->video_pid_len) {
struct dvb_open_descriptor *video_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!video_fd) {
ERROR("failed opening '%s'", args.demux_dev);
goto err;
}
fprintf(stderr, _("dvb_dev_set_bufsize: buffer set to %d\n"), DVB_BUF_SIZE);
dvb_dev_set_bufsize(video_fd, DVB_BUF_SIZE);
if (args.n_vpid >= dvb_entry->video_pid_len) {
args.n_vpid = 0;
}
for (int i = 0; i < dvb_entry->video_pid_len; i++) {
if (!args.extra_pids && i != args.n_vpid) {
continue;
}
if (args.silent < 2) {
fprintf(stderr, _("video%2$s pid %1$d\n"),
dvb_entry->video_pid[i], i == args.n_vpid ? "" : "+");
}
if (dvb_dev_dmx_set_pesfilter(video_fd, dvb_entry->video_pid[i],
i == args.n_vpid ? DMX_PES_VIDEO : DMX_PES_OTHER,
args.dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER,
args.dvr ? 1024 * 1024 : 0) < 0) {
goto err;
}
}
}
if (dvb_entry->audio_pid_len) {
if (args.n_apid >= dvb_entry->audio_pid_len) {
args.n_apid = 0;
}
for (int i = 0; i < dvb_entry->audio_pid_len; i++) {
if (!args.extra_pids && i != args.n_apid) {
continue;
}
struct dvb_open_descriptor *audio_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!audio_fd) {
ERROR("failed opening '%s'", args.demux_dev);
goto err;
}
if (args.silent < 2) {
fprintf(stderr, _("audio%2$s pid %1$d\n"),
dvb_entry->audio_pid[i], i == args.n_apid ? "" : "+");
}
if (dvb_dev_dmx_set_pesfilter(audio_fd, dvb_entry->audio_pid[i],
i == args.n_apid ? DMX_PES_AUDIO : DMX_PES_OTHER,
args.dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER,
args.dvr ? 64 * 1024 : 0) < 0) {
goto err;
}
}
}
if (args.extra_pids && dvb_entry->other_el_pid_len) {
for (int i = dvb_entry->other_el_pid_len - 1; i >= 0; i--) {
struct dvb_open_descriptor * other_fd = dvb_dev_open(dvb, args.demux_dev, O_RDWR);
if (!other_fd) {
ERROR("failed opening '%s'", args.demux_dev);
goto err;
}
if (args.silent < 2) {
fprintf(stderr, _("other pid %d (%d)\n"),
dvb_entry->other_el_pid[i].pid, dvb_entry->other_el_pid[i].type);
}
if (dvb_dev_dmx_set_pesfilter(other_fd, dvb_entry->other_el_pid[i].pid, DMX_PES_OTHER,
args.dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER,
args.dvr ? 64 * 1024 : 0) < 0) {
goto err;
}
}
}
}
if ((dvb_entry->video_pid_len || dvb_entry->audio_pid_len) && !args.all_pids && !args.rec_psi) {
printf(_("PMT record is disabled.\n"
"Please notice that some streams can only be decoded with PMT data.\n"
"Use '-p' option to also record PMT.\n"));
}
set_signals(&args);
if (!check_frontend(&args, parms)) {
err = 1;
fprintf(stderr, _("frontend doesn't lock\n"));
goto err;
}
if (args.dvr) {
if (args.filename) {
file_fd = STDOUT_FILENO;
if (strcmp(args.filename, "-") != 0) {
file_fd = open(args.filename,
O_LARGEFILE |
O_WRONLY | O_CREAT | O_TRUNC,
0644);
if (file_fd < 0) {
PERROR(_("open of '%s' failed"),
args.filename);
return -1;
}
}
}
if (args.silent < 2)
get_show_stats(stderr, &args, parms, 0);
if (file_fd >= 0) {
dvr_fd = dvb_dev_open(dvb, args.dvr_dev, O_RDONLY);
if (!dvr_fd) {
ERROR("failed opening '%s'", args.dvr_dev);
goto err;
}
if (!timeout_flag)
fprintf(stderr, _("Record to file '%s' started\n"), args.filename);
copy_to_file(dvr_fd, file_fd, args.timeout, args.silent);
} else if (args.server && args.port) {
struct stat st;
if (stat(args.dvr_pipe, &st) == -1) {
if (mknod(args.dvr_pipe,
S_IRUSR | S_IWUSR | S_IFIFO, 0) < 0) {
PERROR("Can't create pipe %s",
args.dvr_pipe);
return -1;
}
} else {
if (!S_ISFIFO(st.st_mode)) {
ERROR("%s exists but is not a pipe",
args.dvr_pipe);
return -1;
}
}
fprintf(stderr, _("DVR pipe interface '%s' will be opened\n"), args.dvr_pipe);
dvr_fd = dvb_dev_open(dvb, args.dvr_dev, O_RDONLY);
if (!dvr_fd) {
ERROR("failed opening '%s'", args.dvr_dev);
err = -1;
goto err;
}
file_fd = open(args.dvr_pipe,
#ifdef O_LARGEFILE
O_LARGEFILE |
#endif
O_WRONLY,
0644);
if (file_fd < 0) {
PERROR(_("open of '%s' failed"),
args.filename);
err = -1;
goto err;
}
copy_to_file(dvr_fd, file_fd, args.timeout, args.silent);
} else {
if (!timeout_flag)
fprintf(stderr, _("DVR interface '%s' can now be opened\n"), args.dvr_fname);
get_show_stats(stderr, &args, parms, 1);
}
if (args.silent < 2)
get_show_stats(stderr, &args, parms, 0);
} else {
/* Wait until timeout or being killed */
while (!timeout_flag) {
get_show_stats(stderr, &args, parms, 1);
usleep(1000000);
}
}
err = 0;
err:
dvb_dev_free(dvb);
if (dvb_file) {
dvb_file_free(dvb_file);
}
/*
* Just to make Valgrind happier. It should be noticed
* That, if an error happens or if the program exits via
* timeout code at forced mode, it may not free those.
*/
if (args.confname)
free(args.confname);
if (args.filename)
free(args.filename);
if (args.lnb_name)
free(args.lnb_name);
if (args.search)
free(args.search);
if (args.server)
free(args.server);
if (args.dvr_pipe != default_dvr_pipe)
free(args.dvr_pipe);
return err;
}
countries.h
Provides ancillary code to convert ISO 3166-1 country codes.
dvb-demux.h
Provides interfaces to deal with DVB demux.
dvb-dev.h
Provides interfaces to handle Digital TV devices.
dvb_dev_remote_init
static int dvb_dev_remote_init(struct dvb_device *d, char *server, int port)
Definition dvb-dev.h:498
dvb_dev_seek_by_adapter
struct dvb_dev_list * dvb_dev_seek_by_adapter(struct dvb_device *dvb, unsigned int adapter, unsigned int num, enum dvb_dev_type type)
Find a device that matches the search criteria given by this functions's parameters.
DVB_DEVICE_DEMUX
@ DVB_DEVICE_DEMUX
Definition dvb-dev.h:60
DVB_DEVICE_FRONTEND
@ DVB_DEVICE_FRONTEND
Definition dvb-dev.h:59
DVB_DEVICE_DVR
@ DVB_DEVICE_DVR
Definition dvb-dev.h:61
dvb-file.h
Provides interfaces to deal with DVB channel and program files.
FILE_UNKNOWN
@ FILE_UNKNOWN
File format is unknown.
Definition dvb-file.h:233
FILE_DVBV5
@ FILE_DVBV5
File is at libdvbv5 format.
Definition dvb-file.h:236
dvb-scan.h
Provides interfaces to scan programs inside MPEG-TS digital TV streams.
dvb_dev_free
void dvb_dev_free(struct dvb_device *dvb)
free a struct dvb_device
dvb_dev_open
struct dvb_open_descriptor * dvb_dev_open(struct dvb_device *dvb, const char *sysname, int flags)
Opens a dvb device.
dvb_dev_dmx_get_pmt_pid
int dvb_dev_dmx_get_pmt_pid(struct dvb_open_descriptor *open_dev, int sid)
read the contents of the MPEG-TS PAT table, seeking for an specific service ID
dvb_dev_dmx_set_pesfilter
int dvb_dev_dmx_set_pesfilter(struct dvb_open_descriptor *open_dev, int pid, dmx_pes_type_t type, dmx_output_t output, int buffersize)
Start a filter for a MPEG-TS Packetized Elementary Stream (PES).
dvb_dev_find
int dvb_dev_find(struct dvb_device *dvb, dvb_dev_change_t handler, void *user_priv)
finds all DVB devices on the local machine
dvb_dev_set_bufsize
int dvb_dev_set_bufsize(struct dvb_open_descriptor *open_dev, int buffersize)
Start a demux or dvr buffer size.
dvb_dev_set_log
void dvb_dev_set_log(struct dvb_device *dvb, unsigned verbose, dvb_logfunc logfunc)
Sets the DVB verbosity and log function.
dvb_dev_read
ssize_t dvb_dev_read(struct dvb_open_descriptor *open_dev, void *buf, size_t count)
read from a dvb demux or dvr file
dvb_dev_alloc
struct dvb_device * dvb_dev_alloc(void)
Allocate a struct dvb_device.
dvb_dev_close
void dvb_dev_close(struct dvb_open_descriptor *open_dev)
Closes a dvb device.
dvb_file_formats
dvb_file_formats
Known file formats.
Definition dvb-file.h:232
dvb_read_file_format
struct dvb_file * dvb_read_file_format(const char *fname, uint32_t delsys, enum dvb_file_formats format)
Read a file on any format natively supported by the library.
dvb_retrieve_entry_prop
int dvb_retrieve_entry_prop(struct dvb_entry *entry, uint32_t cmd, uint32_t *value)
Retrieves the value associated witha key on a DVB file entry.
dvb_file_free
static void dvb_file_free(struct dvb_file *dvb_file)
Deallocates memory associated with a struct dvb_file.
Definition dvb-file.h:255
dvb_parse_format
enum dvb_file_formats dvb_parse_format(const char *name)
Ancillary function that parses the name of a file format.
dvb_fe_set_default_country
int dvb_fe_set_default_country(struct dvb_v5_fe_parms *parms, const char *country)
Set default country variant of delivery systems like ISDB-T.
DTV_BER
#define DTV_BER
Bit Error Rate.
Definition dvb-v5-std.h:200
dvb_fe_retrieve_stats
int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *parms, unsigned cmd, uint32_t *value)
Retrieve the stats for a DTV layer from cache.
dvb_fe_store_parm
int dvb_fe_store_parm(struct dvb_v5_fe_parms *parms, unsigned cmd, uint32_t value)
Stores the value of a DVBv5/libdvbv5 property.
dvb_fe_snprintf_stat
int dvb_fe_snprintf_stat(struct dvb_v5_fe_parms *parms, uint32_t cmd, char *display_name, int layer, char **buf, int *len, int *show_layer_name)
Ancillary function to sprintf on ENG format.
dvb_set_compat_delivery_system
int dvb_set_compat_delivery_system(struct dvb_v5_fe_parms *parms, uint32_t desired_system)
Sets the delivery system.
DTV_STATUS
#define DTV_STATUS
Lock status of a DTV frontend.
Definition dvb-v5-std.h:199
dvb_fe_retrieve_parm
int dvb_fe_retrieve_parm(const struct dvb_v5_fe_parms *parms, unsigned cmd, uint32_t *value)
Retrieves the value of a DVBv5/libdvbv5 property.
DTV_QUALITY
#define DTV_QUALITY
A quality indicator that represents if a locked channel provides a good, OK or poor signal.
Definition dvb-v5-std.h:202
DTV_PER
#define DTV_PER
Packet Error Rate.
Definition dvb-v5-std.h:201
dvb_fe_set_parms
int dvb_fe_set_parms(struct dvb_v5_fe_parms *parms)
Prints all the properties at the cache.
DTV_PRE_BER
#define DTV_PRE_BER
Bit Error Rate before Viterbi.
Definition dvb-v5-std.h:203
dvb_fe_get_stats
int dvb_fe_get_stats(struct dvb_v5_fe_parms *parms)
Retrieve the stats from the Kernel.
dvb_print_all_lnb
void dvb_print_all_lnb(void)
Prints all LNBf entries at STDOUT.
dvb_print_lnb
int dvb_print_lnb(int index)
prints the contents of a LNBf entry at STDOUT.
dvb_sat_get_lnb
const struct dvb_sat_lnb * dvb_sat_get_lnb(int index)
gets a LNBf entry at its internal database
dvb_sat_search_lnb
int dvb_sat_search_lnb(const char *name)
search for a LNBf entry
header.h
Provides the MPEG TS table headers.
dvb_dev_list
Digital TV device node properties.
Definition dvb-dev.h:86
dvb_dev_list::sysname
char * sysname
Definition dvb-dev.h:89
dvb_dev_list::path
char * path
Definition dvb-dev.h:88
dvb_device
Digital TV list of devices.
Definition dvb-dev.h:140
dvb_device::fe_parms
struct dvb_v5_fe_parms * fe_parms
Definition dvb-dev.h:146
dvb_elementary_pid::pid
uint16_t pid
Definition dvb-file.h:60
dvb_elementary_pid::type
uint8_t type
Definition dvb-file.h:59
dvb_entry
Represents one entry on a DTV file.
Definition dvb-file.h:104
dvb_entry::audio_pid_len
unsigned audio_pid_len
Definition dvb-file.h:111
dvb_entry::lnb
char * lnb
Definition dvb-file.h:120
dvb_entry::n_props
unsigned int n_props
Definition dvb-file.h:106
dvb_entry::props
struct dtv_property props[DTV_MAX_COMMAND]
Definition dvb-file.h:105
dvb_entry::other_el_pid
struct dvb_elementary_pid * other_el_pid
Definition dvb-file.h:110
dvb_entry::video_pid
uint16_t * video_pid
Definition dvb-file.h:109
dvb_entry::audio_pid
uint16_t * audio_pid
Definition dvb-file.h:109
dvb_entry::video_pid_len
unsigned video_pid_len
Definition dvb-file.h:111
dvb_entry::other_el_pid_len
unsigned other_el_pid_len
Definition dvb-file.h:111
dvb_entry::channel
char * channel
Definition dvb-file.h:112
dvb_entry::service_id
uint16_t service_id
Definition dvb-file.h:108
dvb_entry::next
struct dvb_entry * next
Definition dvb-file.h:107
dvb_entry::sat_number
int sat_number
Definition dvb-file.h:117
dvb_entry::vchannel
char * vchannel
Definition dvb-file.h:113
dvb_file
Describes an entire DVB file opened.
Definition dvb-file.h:135
dvb_file::first_entry
struct dvb_entry * first_entry
Definition dvb-file.h:138
dvb_open_descriptor
Opaque struct with a DVB open file descriptor.
dvb_ts_packet_header
Header of a MPEG-TS transport packet.
Definition header.h:57
dvb_ts_packet_header::pid
uint16_t pid
Definition header.h:62
dvb_ts_packet_header::sync_byte
uint8_t sync_byte
Definition header.h:58
dvb_ts_packet_header::adaptation_field_length
uint8_t adaptation_field_length
Definition header.h:73
dvb_ts_packet_header::discontinued
uint8_t discontinued
Definition header.h:83
dvb_ts_packet_header::adaptation_field_control
uint8_t adaptation_field_control
Definition header.h:69
dvb_ts_packet_header::continuity_counter
uint8_t continuity_counter
Definition header.h:68
dvb_ts_packet_header::bitfield
uint16_t bitfield
Definition header.h:60
dvb_v5_fe_parms
Keeps data needed to handle the DVB frontend.
Definition dvb-fe.h:117
dvb_v5_fe_parms::lna
int lna
Definition dvb-fe.h:133
dvb_v5_fe_parms::freq_bpf
unsigned freq_bpf
Definition dvb-fe.h:138
dvb_v5_fe_parms::diseqc_wait
unsigned diseqc_wait
Definition dvb-fe.h:139
dvb_v5_fe_parms::sat_number
int sat_number
Definition dvb-fe.h:137
dvb_v5_fe_parms::lnb
const struct dvb_sat_lnb * lnb
Definition dvb-fe.h:136
dvb_v5_fe_parms::current_sys
fe_delivery_system_t current_sys
Definition dvb-fe.h:122