diff --git a/Makefile b/Makefile index ff1addf6..800d4ae6 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,7 @@ SRCS = src/main.c \ src/parachute.c \ src/avg.c \ src/htsstr.c \ + src/rawtsinput.c \ SRCS += src/dvr/dvr_db.c \ src/dvr/dvr_rec.c \ diff --git a/src/main.c b/src/main.c index 54a9a22c..c5124b25 100644 --- a/src/main.c +++ b/src/main.c @@ -50,6 +50,7 @@ #include "cwc.h" #include "dvr/dvr.h" #include "htsp.h" +#include "rawtsinput.h" #include "parachute.h" #include "settings.h" @@ -228,8 +229,9 @@ main(int argc, char **argv) sigset_t set; const char *contentpath = TVHEADEND_CONTENT_PATH; const char *homedir = NULL; + const char *rawts_input = NULL; - while((c = getopt(argc, argv, "fu:g:c:Chd")) != -1) { + while((c = getopt(argc, argv, "fu:g:c:Chdr:")) != -1) { switch(c) { case 'f': forkaway = 1; @@ -249,6 +251,9 @@ main(int argc, char **argv) case 'C': createdefault = 1; break; + case 'r': + rawts_input = optarg; + break; default: usage(argv[0]); } @@ -338,6 +343,9 @@ main(int argc, char **argv) dvr_init(); htsp_init(); + + if(rawts_input != NULL) + rawts_init(rawts_input); pthread_mutex_unlock(&global_lock); diff --git a/src/rawtsinput.c b/src/rawtsinput.c new file mode 100644 index 00000000..ba99d4d7 --- /dev/null +++ b/src/rawtsinput.c @@ -0,0 +1,310 @@ +/* + * Raw TS input (for debugging) + * Copyright (C) 2009 Andreas Ă–man + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tvhead.h" +#include "transports.h" +#include "rawtsinput.h" +#include "psi.h" +#include "tsdemux.h" + +typedef struct rawts { + int rt_fd; + + char *rt_identifier; + psi_section_t rt_pat; + + struct th_transport_list rt_transports; + +} rawts_t; + + +/** + * + */ +static int +rawts_transport_start(th_transport_t *t, unsigned int weight, int status, + int force_start) +{ + return 0; // Always ok +} + +/** + * + */ +static void +rawts_transport_stop(th_transport_t *t) +{ + +} + +/** + * + */ +static void +rawts_transport_save(th_transport_t *t) +{ +} + + +/** + * + */ +static int +rawts_transport_quality(th_transport_t *t) +{ + return 100; +} + + +/** + * Generate a descriptive name for the source + */ +static const char * +rawts_transport_sourcename(th_transport_t *t) +{ + return "rawts"; +} + + +/** + * Generate a descriptive name for the source + */ +static const char * +rawts_transport_networkname(th_transport_t *t) +{ + return "rawts"; +} + + + +/** + * + */ +static th_transport_t * +rawts_transport_add(rawts_t *rt, uint16_t sid, int pmt_pid) +{ + th_transport_t *t; + channel_t *ch; + + char tmp[200]; + + LIST_FOREACH(t, &rt->rt_transports, tht_mux_link) { + if(t->tht_dvb_service_id == sid) + return t; + } + + snprintf(tmp, sizeof(tmp), "%s_%04x", rt->rt_identifier, sid); + + t = transport_create(tmp, TRANSPORT_DVB, THT_MPEG_TS); + t->tht_flags |= THT_DEBUG; + + t->tht_dvb_service_id = sid; + t->tht_pmt_pid = pmt_pid; + + t->tht_start_feed = rawts_transport_start; + t->tht_stop_feed = rawts_transport_stop; + t->tht_config_change = rawts_transport_save; + t->tht_sourcename = rawts_transport_sourcename; + t->tht_networkname = rawts_transport_networkname; + t->tht_quality_index = rawts_transport_quality; + + t->tht_svcname = strdup(tmp); + + tvhlog(LOG_NOTICE, "rawts", "Added service %d (pmt: %d)", sid, pmt_pid); + + LIST_INSERT_HEAD(&rt->rt_transports, t, tht_mux_link); + + ch = channel_find_by_name(tmp, 1); + + transport_map_channel(t, ch); + return t; +} + + +/* + * + */ + +static void +got_pmt(struct th_transport *t, th_stream_t *st, + uint8_t *table, int table_len) +{ + if(table[0] != 2) + return; + + pthread_mutex_lock(&global_lock); + psi_parse_pmt(t, table + 3, table_len - 3, 1); + pthread_mutex_unlock(&global_lock); +} + + + +/** + * + */ +static void +got_pat(rawts_t *rt) +{ + th_transport_t *t; + th_stream_t *st; + int len = rt->rt_pat.ps_offset; + uint8_t *ptr = rt->rt_pat.ps_data; + uint16_t prognum; + uint16_t pid; + + len -= 8; + ptr += 8; + + if(len < 0) + return; + + pthread_mutex_lock(&global_lock); + + while(len >= 4) { + + prognum = ptr[0] << 8 | ptr[1]; + pid = (ptr[2] & 0x1f) << 8 | ptr[3]; + + if(prognum != 0) { + t = rawts_transport_add(rt, prognum, pid); + + if(t != NULL) { + pthread_mutex_lock(&t->tht_stream_mutex); + st = transport_add_stream(t, pid, SCT_PMT); + st->st_section_docrc = 1; + st->st_got_section = got_pmt; + pthread_mutex_unlock(&t->tht_stream_mutex); + } + } + ptr += 4; + len -= 4; + } + pthread_mutex_unlock(&global_lock); +} + +/** + * + */ +static void +rawts_pat(rawts_t *rt, uint8_t *tsb) +{ + int off = tsb[3] & 0x20 ? tsb[4] + 5 : 4; + int pusi = tsb[1] & 0x40; + int len; + + if(off >= 188) + return; + + if(pusi) { + len = tsb[off++]; + if(len > 0) { + if(len > 188 - off) + return; + if(!psi_section_reassemble(&rt->rt_pat, tsb + off, len, 0, 1)) + got_pat(rt); + off += len; + } + } + + if(!psi_section_reassemble(&rt->rt_pat, tsb + off, 188 - off, pusi, 1)) + got_pat(rt); +} + + +/** + * + */ +static void +process_ts_packet(rawts_t *rt, uint8_t *tsb) +{ + uint16_t pid; + th_transport_t *t; + + pid = ((tsb[1] & 0xf) << 8) | tsb[2]; + + if(pid == 0) { + /* PAT */ + rawts_pat(rt, tsb); + return; + } + + LIST_FOREACH(t, &rt->rt_transports, tht_mux_link) + ts_recv_packet1(t, tsb); +} + + +/** + * + */ +static void * +raw_ts_reader(void *aux) +{ + rawts_t *rt = aux; + uint8_t tsblock[188]; + int c = 0; + int i; + + while(1) { + + for(i = 0; i < 2; i++) { + if(read(rt->rt_fd, tsblock, 188) != 188) { + lseek(rt->rt_fd, 0, SEEK_SET); + continue; + } + c++; + process_ts_packet(rt, tsblock); + } + usleep(1000); + } + + return NULL; +} + + +/** + * + */ +void +rawts_init(const char *filename) +{ + pthread_t ptid; + rawts_t *rt; + int fd = open(filename, O_RDONLY); + + if(fd == -1) { + fprintf(stderr, "Unable to open %s -- %s\n", filename, strerror(errno)); + return; + } + + rt = calloc(1, sizeof(rawts_t)); + rt->rt_fd = fd; + + rt->rt_identifier = strdup("rawts"); + + pthread_create(&ptid, NULL, raw_ts_reader, rt); +} diff --git a/src/rawtsinput.h b/src/rawtsinput.h new file mode 100644 index 00000000..d007a632 --- /dev/null +++ b/src/rawtsinput.h @@ -0,0 +1,4 @@ + + +void rawts_init(const char *filename); +