|
|
@@ -0,0 +1,677 @@
|
|
|
+#define _FILE_OFFSET_BITS 64
|
|
|
+#define _LARGEFILE_SOURCE 1
|
|
|
+#define _LARGEFILE64_SOURCE 1
|
|
|
+
|
|
|
+/******************************** INCLUDE FILES *******************************/
|
|
|
+#include <sys/types.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <sys/ioctl.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <stdint.h>
|
|
|
+#include <string.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <ctype.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <signal.h>
|
|
|
+
|
|
|
+#include <linux/dvb/frontend.h>
|
|
|
+#include <linux/dvb/dmx.h>
|
|
|
+
|
|
|
+#include "util.h"
|
|
|
+
|
|
|
+/******************************* LOCAL TYPEDEFS ******************************/
|
|
|
+
|
|
|
+
|
|
|
+/********************************* LOCAL DATA *********************************/
|
|
|
+static char FRONTEND_DEV [80];
|
|
|
+static char DEMUX_DEV [80];
|
|
|
+static char DVR_DEV [80];
|
|
|
+static int timeout_flag=0;
|
|
|
+static int silent=0,timeout=0;
|
|
|
+static int exit_after_tuning;
|
|
|
+
|
|
|
+/******************************** LOCAL DEFINES *******************************/
|
|
|
+#define CHANNEL_FILE "channels.conf"
|
|
|
+
|
|
|
+#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)
|
|
|
+
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ char *name;
|
|
|
+ int value;
|
|
|
+} Param;
|
|
|
+
|
|
|
+static const Param inversion_list [] = {
|
|
|
+ { "INVERSION_OFF", INVERSION_OFF },
|
|
|
+ { "INVERSION_ON", INVERSION_ON },
|
|
|
+ { "INVERSION_AUTO", INVERSION_AUTO }
|
|
|
+};
|
|
|
+
|
|
|
+static const Param bw_list [] = {
|
|
|
+ { "BANDWIDTH_6_MHZ", BANDWIDTH_6_MHZ },
|
|
|
+ { "BANDWIDTH_7_MHZ", BANDWIDTH_7_MHZ },
|
|
|
+ { "BANDWIDTH_8_MHZ", BANDWIDTH_8_MHZ }
|
|
|
+};
|
|
|
+
|
|
|
+static const Param fec_list [] = {
|
|
|
+ { "FEC_1_2", FEC_1_2 },
|
|
|
+ { "FEC_2_3", FEC_2_3 },
|
|
|
+ { "FEC_3_4", FEC_3_4 },
|
|
|
+ { "FEC_4_5", FEC_4_5 },
|
|
|
+ { "FEC_5_6", FEC_5_6 },
|
|
|
+ { "FEC_6_7", FEC_6_7 },
|
|
|
+ { "FEC_7_8", FEC_7_8 },
|
|
|
+ { "FEC_8_9", FEC_8_9 },
|
|
|
+ { "FEC_AUTO", FEC_AUTO },
|
|
|
+ { "FEC_NONE", FEC_NONE }
|
|
|
+};
|
|
|
+
|
|
|
+static const Param guard_list [] = {
|
|
|
+ {"GUARD_INTERVAL_1_16", GUARD_INTERVAL_1_16},
|
|
|
+ {"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32},
|
|
|
+ {"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4},
|
|
|
+ {"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8},
|
|
|
+ {"GUARD_INTERVAL_AUTO", GUARD_INTERVAL_AUTO}
|
|
|
+};
|
|
|
+
|
|
|
+static const Param hierarchy_list [] = {
|
|
|
+ { "HIERARCHY_1", HIERARCHY_1 },
|
|
|
+ { "HIERARCHY_2", HIERARCHY_2 },
|
|
|
+ { "HIERARCHY_4", HIERARCHY_4 },
|
|
|
+ { "HIERARCHY_NONE", HIERARCHY_NONE },
|
|
|
+ { "HIERARCHY_AUTO", HIERARCHY_AUTO }
|
|
|
+};
|
|
|
+
|
|
|
+static const Param constellation_list [] = {
|
|
|
+ { "QPSK", QPSK },
|
|
|
+ { "QAM_128", QAM_128 },
|
|
|
+ { "QAM_16", QAM_16 },
|
|
|
+ { "QAM_256", QAM_256 },
|
|
|
+ { "QAM_32", QAM_32 },
|
|
|
+ { "QAM_64", QAM_64 },
|
|
|
+ { "QAM_AUTO", QAM_AUTO }
|
|
|
+};
|
|
|
+
|
|
|
+static const Param transmissionmode_list [] = {
|
|
|
+ { "TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K },
|
|
|
+ { "TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K },
|
|
|
+ { "TRANSMISSION_MODE_AUTO", TRANSMISSION_MODE_AUTO }
|
|
|
+};
|
|
|
+
|
|
|
+#define LIST_SIZE(x) sizeof(x)/sizeof(Param)
|
|
|
+
|
|
|
+static int parse_param (int fd, const Param * plist, int list_size, int *param)
|
|
|
+{
|
|
|
+ char c;
|
|
|
+ int character = 0;
|
|
|
+ int _index = 0;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ if (read(fd, &c, 1) < 1)
|
|
|
+ return -1; /* EOF? */
|
|
|
+
|
|
|
+ if ((c == ':' || c == '\n')
|
|
|
+ && plist->name[character] == '\0')
|
|
|
+ break;
|
|
|
+
|
|
|
+ while (toupper(c) != plist->name[character]) {
|
|
|
+ _index++;
|
|
|
+ plist++;
|
|
|
+ if (_index >= list_size) /* parse error, no valid */
|
|
|
+ return -2; /* parameter name found */
|
|
|
+ }
|
|
|
+
|
|
|
+ character++;
|
|
|
+ }
|
|
|
+
|
|
|
+ *param = plist->value;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int parse_int(int fd, int *val)
|
|
|
+{
|
|
|
+ char number[11]; /* 2^32 needs 10 digits... */
|
|
|
+ int character = 0;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ if (read(fd, &number[character], 1) < 1)
|
|
|
+ return -1; /* EOF? */
|
|
|
+
|
|
|
+ if (number[character] == ':' || number[character] == '\n') {
|
|
|
+ number[character] = '\0';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isdigit(number[character]))
|
|
|
+ return -2; /* parse error, not a digit... */
|
|
|
+
|
|
|
+ character++;
|
|
|
+
|
|
|
+ if (character > 10) /* overflow, number too big */
|
|
|
+ return -3; /* to fit in 32 bit */
|
|
|
+ };
|
|
|
+
|
|
|
+ errno = 0;
|
|
|
+ *val = strtol(number, NULL, 10);
|
|
|
+ if (errno == ERANGE)
|
|
|
+ return -4;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int find_channel(int fd, const char *channel)
|
|
|
+{
|
|
|
+ int character = 0;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ char c;
|
|
|
+
|
|
|
+ if (read(fd, &c, 1) < 1)
|
|
|
+ return -1; /* EOF! */
|
|
|
+
|
|
|
+ if ( '\n' == c ) /* start of line */
|
|
|
+ character = 0;
|
|
|
+ else if ( character >= 0 ) { /* we are in the namefield */
|
|
|
+
|
|
|
+ if (c == ':' && channel[character] == '\0')
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (toupper(c) == toupper(channel[character]))
|
|
|
+ character++;
|
|
|
+ else
|
|
|
+ character = -1;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static
|
|
|
+int try_parse_int(int fd, int *val, const char *pname)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = parse_int(fd, val);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ ERROR("error while parsing %s (%s)", pname,
|
|
|
+ err == -1 ? "end of file" :
|
|
|
+ err == -2 ? "not a number" : "number too big");
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static
|
|
|
+int try_parse_param(int fd, const Param * plist, int list_size, int *param,
|
|
|
+ const char *pname)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = parse_param(fd, plist, list_size, param);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ ERROR("error while parsing %s (%s)", pname,
|
|
|
+ err == -1 ? "end of file" : "syntax error");
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int check_fec(fe_code_rate_t *fec)
|
|
|
+{
|
|
|
+ switch (*fec)
|
|
|
+ {
|
|
|
+ case FEC_NONE:
|
|
|
+ *fec = FEC_AUTO;
|
|
|
+ case FEC_AUTO:
|
|
|
+ case FEC_1_2:
|
|
|
+ case FEC_2_3:
|
|
|
+ case FEC_3_4:
|
|
|
+ case FEC_5_6:
|
|
|
+ case FEC_7_8:
|
|
|
+ return 0;
|
|
|
+ default:
|
|
|
+ ;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int parse(const char *fname, const char *channel,
|
|
|
+ struct dvb_frontend_parameters *frontend, int *vpid, int *apid,
|
|
|
+ int *sid)
|
|
|
+{
|
|
|
+ int fd;
|
|
|
+ int err;
|
|
|
+ int tmp;
|
|
|
+
|
|
|
+ if ((fd = open(fname, O_RDONLY | O_NONBLOCK)) < 0) {
|
|
|
+ PERROR ("could not open file '%s'", fname);
|
|
|
+ perror ("");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (find_channel(fd, channel) < 0) {
|
|
|
+ ERROR("could not find channel '%s' in channel list", channel);
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((err = try_parse_int(fd, &tmp, "frequency")))
|
|
|
+ return -3;
|
|
|
+ frontend->frequency = tmp;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd,
|
|
|
+ inversion_list, LIST_SIZE(inversion_list),
|
|
|
+ &tmp, "inversion")))
|
|
|
+ return -4;
|
|
|
+ frontend->inversion = tmp;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd, bw_list, LIST_SIZE(bw_list),
|
|
|
+ &tmp, "bandwidth")))
|
|
|
+ return -5;
|
|
|
+ frontend->u.ofdm.bandwidth = tmp;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list),
|
|
|
+ &tmp, "code_rate_HP")))
|
|
|
+ return -6;
|
|
|
+ frontend->u.ofdm.code_rate_HP = tmp;
|
|
|
+ if (check_fec(&frontend->u.ofdm.code_rate_HP))
|
|
|
+ return -6;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list),
|
|
|
+ &tmp, "code_rate_LP")))
|
|
|
+ return -7;
|
|
|
+ frontend->u.ofdm.code_rate_LP = tmp;
|
|
|
+ if (check_fec(&frontend->u.ofdm.code_rate_LP))
|
|
|
+ return -7;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd, constellation_list,
|
|
|
+ LIST_SIZE(constellation_list),
|
|
|
+ &tmp, "constellation")))
|
|
|
+ return -8;
|
|
|
+ frontend->u.ofdm.constellation = tmp;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd, transmissionmode_list,
|
|
|
+ LIST_SIZE(transmissionmode_list),
|
|
|
+ &tmp, "transmission_mode")))
|
|
|
+ return -9;
|
|
|
+ frontend->u.ofdm.transmission_mode = tmp;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd, guard_list, LIST_SIZE(guard_list),
|
|
|
+ &tmp, "guard_interval")))
|
|
|
+ return -10;
|
|
|
+ frontend->u.ofdm.guard_interval = tmp;
|
|
|
+
|
|
|
+ if ((err = try_parse_param(fd, hierarchy_list,
|
|
|
+ LIST_SIZE(hierarchy_list),
|
|
|
+ &tmp, "hierarchy_information")))
|
|
|
+ return -11;
|
|
|
+ frontend->u.ofdm.hierarchy_information = tmp;
|
|
|
+
|
|
|
+ if ((err = try_parse_int(fd, vpid, "Video PID")))
|
|
|
+ return -12;
|
|
|
+
|
|
|
+ if ((err = try_parse_int(fd, apid, "Audio PID")))
|
|
|
+ return -13;
|
|
|
+
|
|
|
+ if ((err = try_parse_int(fd, sid, "Service ID")))
|
|
|
+ return -14;
|
|
|
+
|
|
|
+ close(fd);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int setup_frontend (int fe_fd, struct dvb_frontend_parameters *frontend)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ uint32_t mstd;
|
|
|
+
|
|
|
+ if (check_frontend(fe_fd, FE_OFDM, &mstd) < 0) {
|
|
|
+ close(fe_fd);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ ret = dvbfe_set_delsys(fe_fd, SYS_DVBT);
|
|
|
+ if (ret) {
|
|
|
+ PERROR("SET Delsys failed");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (silent < 2)
|
|
|
+ fprintf (stderr,"tuning to %i Hz\n", frontend->frequency);
|
|
|
+
|
|
|
+ if (ioctl(fe_fd, FE_SET_FRONTEND, frontend) < 0) {
|
|
|
+ PERROR("ioctl FE_SET_FRONTEND 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 */
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void print_frontend_stats(int fe_fd, int human_readable)
|
|
|
+{
|
|
|
+ fe_status_t status;
|
|
|
+ uint16_t snr, _signal;
|
|
|
+ uint32_t ber, uncorrected_blocks;
|
|
|
+
|
|
|
+ ioctl(fe_fd, FE_READ_STATUS, &status);
|
|
|
+ ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &_signal);
|
|
|
+ ioctl(fe_fd, FE_READ_SNR, &snr);
|
|
|
+ ioctl(fe_fd, FE_READ_BER, &ber);
|
|
|
+ ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
|
|
|
+
|
|
|
+ if (human_readable) {
|
|
|
+ printf ("status %02x | signal %3u%% | snr %3u%% | ber %d | unc %d | ",
|
|
|
+ status, (_signal * 100) / 0xffff, (snr * 100) / 0xffff, ber, uncorrected_blocks);
|
|
|
+ } else {
|
|
|
+ fprintf (stderr, "status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
|
|
|
+ status, _signal, snr, ber, uncorrected_blocks);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (status & FE_HAS_LOCK)
|
|
|
+ fprintf(stderr,"FE_HAS_LOCK");
|
|
|
+
|
|
|
+ fprintf(stderr,"\n");
|
|
|
+}
|
|
|
+
|
|
|
+static
|
|
|
+int monitor_frontend (int fe_fd, int human_readable)
|
|
|
+{
|
|
|
+ fe_status_t status;
|
|
|
+ do {
|
|
|
+ ioctl(fe_fd, FE_READ_STATUS, &status);
|
|
|
+ if (!silent)
|
|
|
+ print_frontend_stats(fe_fd, human_readable);
|
|
|
+ if (exit_after_tuning && (status & FE_HAS_LOCK))
|
|
|
+ break;
|
|
|
+ usleep(1000000);
|
|
|
+ } while (!timeout_flag);
|
|
|
+ if (silent < 2)
|
|
|
+ print_frontend_stats (fe_fd, human_readable);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#define BUFLEN (188*256)
|
|
|
+static void copy_to_file(int in_fd, int out_fd)
|
|
|
+{
|
|
|
+ char buf[BUFLEN];
|
|
|
+ int r;
|
|
|
+ long long int rc = 0LL;
|
|
|
+
|
|
|
+ while (timeout_flag==0) {
|
|
|
+ r=read(in_fd,buf,BUFLEN);
|
|
|
+ if (r < 0) {
|
|
|
+ if (errno == EOVERFLOW) {
|
|
|
+ printf("buffer overrun\n");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ PERROR("Read failed");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (write(out_fd,buf,r) < 0) {
|
|
|
+ PERROR("Write failed");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ rc+=r;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (silent<2) {
|
|
|
+ fprintf(stderr, "copied %lld bytes (%lld Kbytes/sec)\n",rc,rc/(1024*timeout));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static char *usage =
|
|
|
+ "usage:\n"
|
|
|
+ " tzap [options] <channel_name>\n"
|
|
|
+ " zap to channel channel_name (case insensitive)\n"
|
|
|
+ " -a number : use given adapter (default 0)\n"
|
|
|
+ " -f number : use given frontend (default 0)\n"
|
|
|
+ " -d number : use given demux (default 0)\n"
|
|
|
+ " -c file : read channels list from 'file'\n"
|
|
|
+ " -x : exit after tuning\n"
|
|
|
+ " -r : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
|
|
|
+ " -p : add pat and pmt to TS recording (implies -r)\n"
|
|
|
+ " -s : only print summary\n"
|
|
|
+ " -S : run silently (no output)\n"
|
|
|
+ " -H : human readable output\n"
|
|
|
+ " -F : set up frontend only, don't touch demux\n"
|
|
|
+ " -t number : timeout (seconds)\n"
|
|
|
+ " -o file : output filename (use -o - for stdout)\n"
|
|
|
+ " -h -? : display this help and exit\n";
|
|
|
+
|
|
|
+
|
|
|
+int main(int argc, char **argv)
|
|
|
+{
|
|
|
+ struct dvb_frontend_parameters frontend_param;
|
|
|
+ char *homedir = getenv("HOME");
|
|
|
+ char *confname = NULL;
|
|
|
+ char *channel = NULL;
|
|
|
+ int adapter = 0, frontend = 0, demux = 0, dvr = 0;
|
|
|
+ int vpid, apid, sid, pmtpid = 0;
|
|
|
+ int pat_fd, pmt_fd;
|
|
|
+ int frontend_fd, audio_fd = 0, video_fd = 0, dvr_fd, file_fd;
|
|
|
+ int opt;
|
|
|
+ int record = 0;
|
|
|
+ int frontend_only = 0;
|
|
|
+ char *filename = NULL;
|
|
|
+ int human_readable = 0, rec_psi = 0;
|
|
|
+
|
|
|
+ while ((opt = getopt(argc, argv, "H?hrpxRsFSn:a:f:d:c:t:o:")) != -1) {
|
|
|
+ switch (opt) {
|
|
|
+ case 'a':
|
|
|
+ adapter = strtoul(optarg, NULL, 0);
|
|
|
+ break;
|
|
|
+ case 'f':
|
|
|
+ frontend = strtoul(optarg, NULL, 0);
|
|
|
+ break;
|
|
|
+ case 'd':
|
|
|
+ demux = strtoul(optarg, NULL, 0);
|
|
|
+ break;
|
|
|
+ case 't':
|
|
|
+ timeout = strtoul(optarg, NULL, 0);
|
|
|
+ break;
|
|
|
+ case 'o':
|
|
|
+ filename = strdup(optarg);
|
|
|
+ record=1;
|
|
|
+ /* fall through */
|
|
|
+ case 'r':
|
|
|
+ dvr = 1;
|
|
|
+ break;
|
|
|
+ case 'p':
|
|
|
+ rec_psi = 1;
|
|
|
+ break;
|
|
|
+ case 'x':
|
|
|
+ exit_after_tuning = 1;
|
|
|
+ break;
|
|
|
+ case 'c':
|
|
|
+ confname = optarg;
|
|
|
+ break;
|
|
|
+ case 's':
|
|
|
+ silent = 1;
|
|
|
+ break;
|
|
|
+ case 'S':
|
|
|
+ silent = 2;
|
|
|
+ break;
|
|
|
+ case 'F':
|
|
|
+ frontend_only = 1;
|
|
|
+ break;
|
|
|
+ case 'H':
|
|
|
+ human_readable = 1;
|
|
|
+ break;
|
|
|
+ case '?':
|
|
|
+ case 'h':
|
|
|
+ default:
|
|
|
+ fprintf (stderr, usage, argv[0]);
|
|
|
+ return -1;
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if (optind < argc)
|
|
|
+ channel = argv[optind];
|
|
|
+
|
|
|
+ if (!channel) {
|
|
|
+ fprintf (stderr, usage, argv[0]);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ snprintf(FRONTEND_DEV,
|
|
|
+ sizeof(FRONTEND_DEV),
|
|
|
+ "/dev/dvb/adapter%i/frontend%i",
|
|
|
+ adapter,
|
|
|
+ frontend);
|
|
|
+
|
|
|
+ snprintf(DEMUX_DEV,
|
|
|
+ sizeof(DEMUX_DEV),
|
|
|
+ "/dev/dvb/adapter%i/demux%i",
|
|
|
+ adapter,
|
|
|
+ demux);
|
|
|
+
|
|
|
+ snprintf(DVR_DEV,
|
|
|
+ sizeof(DVR_DEV),
|
|
|
+ "/dev/dvb/adapter%i/dvr%i",
|
|
|
+ adapter,
|
|
|
+ demux);
|
|
|
+
|
|
|
+ if (silent < 2)
|
|
|
+ fprintf (stderr,"using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV);
|
|
|
+
|
|
|
+ if (!confname) {
|
|
|
+ int len = strlen(homedir) + strlen(CHANNEL_FILE) + 18;
|
|
|
+ if (!homedir)
|
|
|
+ ERROR ("$HOME not set");
|
|
|
+ confname = malloc (len);
|
|
|
+ snprintf(confname, len, "%s/.tzap/%i/%s", homedir, adapter, CHANNEL_FILE);
|
|
|
+ if (access (confname, R_OK))
|
|
|
+ snprintf(confname, len, "%s/.tzap/%s", homedir, CHANNEL_FILE);
|
|
|
+ }
|
|
|
+ printf("reading channels from file '%s'\n", confname);
|
|
|
+ memset(&frontend_param, 0, sizeof(struct dvb_frontend_parameters));
|
|
|
+
|
|
|
+ if (parse (confname, channel, &frontend_param, &vpid, &apid, &sid))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if ((frontend_fd = open(FRONTEND_DEV, O_RDWR | O_NONBLOCK)) < 0) {
|
|
|
+ PERROR ("failed opening '%s'", FRONTEND_DEV);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (setup_frontend (frontend_fd, &frontend_param) < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (frontend_only)
|
|
|
+ goto just_the_frontend_dude;
|
|
|
+
|
|
|
+ if (rec_psi) {
|
|
|
+ pmtpid = get_pmt_pid(DEMUX_DEV, sid);
|
|
|
+ if (pmtpid <= 0) {
|
|
|
+ fprintf(stderr,"couldn't find pmt-pid for sid %04x\n",sid);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((pat_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
|
|
|
+ perror("opening pat demux failed");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (set_pesfilter(pat_fd, 0, DMX_PES_OTHER, dvr) < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if ((pmt_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
|
|
|
+ perror("opening pmt demux failed");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (set_pesfilter(pmt_fd, pmtpid, DMX_PES_OTHER, dvr) < 0)
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((video_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
|
|
|
+ PERROR("failed opening '%s'", DEMUX_DEV);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (silent<2)
|
|
|
+ fprintf(stderr,"video pid 0x%04x, audio pid 0x%04x\n", vpid, apid);
|
|
|
+
|
|
|
+ if (set_pesfilter(video_fd, vpid, DMX_PES_VIDEO, dvr) < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if ((audio_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
|
|
|
+ PERROR("failed opening '%s'", DEMUX_DEV);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (set_pesfilter(audio_fd, apid, DMX_PES_AUDIO, dvr) < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ signal(SIGALRM,do_timeout);
|
|
|
+ if (timeout > 0)
|
|
|
+ alarm(timeout);
|
|
|
+
|
|
|
+ if (record) {
|
|
|
+ if (filename!=NULL) {
|
|
|
+ if (strcmp(filename,"-")!=0) {
|
|
|
+ file_fd = open(filename,O_WRONLY|O_LARGEFILE|O_CREAT,0644);
|
|
|
+ if (file_fd<0) {
|
|
|
+ PERROR("open of '%s' failed",filename);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ file_fd=1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ PERROR("Record mode but no filename!");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((dvr_fd = open(DVR_DEV, O_RDONLY)) < 0) {
|
|
|
+ PERROR("failed opening '%s'", DVR_DEV);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (silent<2)
|
|
|
+ print_frontend_stats(frontend_fd, human_readable);
|
|
|
+
|
|
|
+ copy_to_file(dvr_fd,file_fd);
|
|
|
+
|
|
|
+ if (silent<2)
|
|
|
+ print_frontend_stats(frontend_fd, human_readable);
|
|
|
+ } else {
|
|
|
+just_the_frontend_dude:
|
|
|
+ monitor_frontend(frontend_fd, human_readable);
|
|
|
+ }
|
|
|
+
|
|
|
+ close(pat_fd);
|
|
|
+ close(pmt_fd);
|
|
|
+ close(audio_fd);
|
|
|
+ close(video_fd);
|
|
|
+ close(frontend_fd);
|
|
|
+ return 0;
|
|
|
+}
|