diff --git a/Makefile b/Makefile index 99f2127c..c6f685dc 100644 --- a/Makefile +++ b/Makefile @@ -329,6 +329,10 @@ SRCS-${CONFIG_CAPMT} += \ SRCS-${CONFIG_CONSTCW} += \ src/descrambler/constcw.c +# TSDEBUGCW +SRCS-${CONFIG_TSDEBUG} += \ + src/descrambler/tsdebugcw.c + # FFdecsa ifneq ($(CONFIG_DVBCSA),yes) FFDECSA-$(CONFIG_CAPMT) = yes diff --git a/configure b/configure index 16b6c7a2..39dc448f 100755 --- a/configure +++ b/configure @@ -44,6 +44,7 @@ OPTIONS=( "kqueue:no" "dbus_1:auto" "android:no" + "tsdebug:no" ) # @@ -472,6 +473,13 @@ if enabled_or_auto dbus_1; then fi fi +# +# TSDebug +# +if enabled_or_auto tsdebug; then + enable mpegts_dvb +fi + # ########################################################################### # Write config diff --git a/src/descrambler/caclient.c b/src/descrambler/caclient.c index 3e51537e..63fb2f26 100644 --- a/src/descrambler/caclient.c +++ b/src/descrambler/caclient.c @@ -296,6 +296,9 @@ caclient_start ( struct service *t ) if (cac->cac_enabled) cac->cac_start(cac, t); pthread_mutex_unlock(&caclients_mutex); +#if ENABLE_TSDEBUG + tsdebugcw_service_start(t); +#endif } void @@ -344,6 +347,9 @@ caclient_init(void) pthread_mutex_init(&caclients_mutex, NULL); TAILQ_INIT(&caclients); +#if ENABLE_TSDEBUG + tsdebugcw_init(); +#endif if (!(c = hts_settings_load("caclient"))) return; diff --git a/src/descrambler/caclient.h b/src/descrambler/caclient.h index 6a6543ff..2c18f06e 100644 --- a/src/descrambler/caclient.h +++ b/src/descrambler/caclient.h @@ -75,8 +75,14 @@ const char *caclient_get_status(caclient_t *cac); void caclient_init(void); void caclient_done(void); +void tsdebugcw_service_start(struct service *t); +void tsdebugcw_new_keys(struct service *t, int type, uint8_t *odd, uint8_t *even); +void tsdebugcw_go(void); +void tsdebugcw_init(void); + caclient_t *cwc_create(void); caclient_t *capmt_create(void); caclient_t *constcw_create(void); +caclient_t *tsdebugcw_create(void); #endif /* __TVH_CACLIENT_H__ */ diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index d42683eb..a15aa647 100755 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -252,6 +252,40 @@ descrambler_keys ( th_descrambler_t *td, int type, fin: pthread_mutex_unlock(&t->s_stream_mutex); +#if ENABLE_TSDEBUG + if (j) { + tsdebug_packet_t *tp = malloc(sizeof(*tp)); + uint16_t keylen = dr->dr_csa.csa_keylen; + uint16_t sid = ((mpegts_service_t *)td->td_service)->s_dvb_service_id; + uint32_t pos = 0, crc; + mpegts_mux_t *mm = ((mpegts_service_t *)td->td_service)->s_dvb_mux; + if (!mm->mm_active) + return; + pthread_mutex_lock(&mm->mm_active->mmi_input->mi_output_lock); + tp->pos = mm->mm_tsdebug_pos; + memset(tp->pkt, 0xff, sizeof(tp->pkt)); + tp->pkt[pos++] = 0x47; /* sync byte */ + tp->pkt[pos++] = 0x1f; /* PID MSB */ + tp->pkt[pos++] = 0xff; /* PID LSB */ + tp->pkt[pos++] = 0x00; /* CC */ + memcpy(tp->pkt + pos, "TVHeadendDescramblerKeys", 24); + pos += 24; + tp->pkt[pos++] = type & 0xff; + tp->pkt[pos++] = keylen & 0xff; + tp->pkt[pos++] = (sid >> 8) & 0xff; + tp->pkt[pos++] = sid & 0xff; + memcpy(tp->pkt + pos, even, keylen); + memcpy(tp->pkt + pos + keylen, odd, keylen); + pos += 2 * keylen; + crc = tvh_crc32(tp->pkt, pos, 0x859aa5ba); + tp->pkt[pos++] = (crc >> 24) & 0xff; + tp->pkt[pos++] = (crc >> 16) & 0xff; + tp->pkt[pos++] = (crc >> 8) & 0xff; + tp->pkt[pos++] = crc & 0xff; + TAILQ_INSERT_HEAD(&mm->mm_tsdebug_packets, tp, link); + pthread_mutex_unlock(&mm->mm_active->mmi_input->mi_output_lock); + } +#endif } static void diff --git a/src/descrambler/tsdebugcw.c b/src/descrambler/tsdebugcw.c new file mode 100644 index 00000000..c50230f5 --- /dev/null +++ b/src/descrambler/tsdebugcw.c @@ -0,0 +1,169 @@ +/* + * tvheadend, tsdebug code word interface + * Copyright (C) 2014 Jaroslav Kysela + * + * 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 "tvheadend.h" +#include "caclient.h" +#include "service.h" +#include "input.h" + +/** + * + */ +typedef struct tsdebugcw_service { + th_descrambler_t; + + int tdcw_type; + uint8_t tdcw_key_even[16]; /* DES or AES key */ + uint8_t tdcw_key_odd [16]; /* DES or AES key */ + +} tsdebugcw_service_t; + +typedef struct tsdebugcw_request { + TAILQ_ENTRY(tsdebugcw_request) link; + tsdebugcw_service_t *ct; +} tsdebugcw_request_t; + +pthread_mutex_t tsdebugcw_mutex; +TAILQ_HEAD(,tsdebugcw_request) tsdebugcw_requests; + +/* + * + */ +static int +tsdebugcw_ecm_reset(th_descrambler_t *th) +{ + return 1; +} + +/** + * s_stream_mutex is held + */ +static void +tsdebugcw_service_destroy(th_descrambler_t *td) +{ + tsdebugcw_service_t *ct = (tsdebugcw_service_t *)td; + tsdebugcw_request_t *ctr, *ctrnext; + + pthread_mutex_lock(&tsdebugcw_mutex); + for (ctr = TAILQ_FIRST(&tsdebugcw_requests); ctr; ctr = ctrnext) { + ctrnext = TAILQ_NEXT(ctr, link); + if (ctr->ct == ct) { + TAILQ_REMOVE(&tsdebugcw_requests, ctr, link); + free(ctr); + } + } + pthread_mutex_unlock(&tsdebugcw_mutex); + + LIST_REMOVE(td, td_service_link); + free(ct->td_nicename); + free(ct); +} + +/** + * global_lock is held. Not that we care about that, but either way, it is. + */ +void +tsdebugcw_service_start(service_t *t) +{ + tsdebugcw_service_t *ct; + th_descrambler_t *td; + char buf[128]; + + extern const idclass_t mpegts_service_class; + if (!idnode_is_instance(&t->s_id, &mpegts_service_class)) + return; + + LIST_FOREACH(td, &t->s_descramblers, td_service_link) + if (td->td_stop == tsdebugcw_service_destroy) + break; + if (td) + return; + + ct = calloc(1, sizeof(tsdebugcw_service_t)); + td = (th_descrambler_t *)ct; + snprintf(buf, sizeof(buf), "tsdebugcw"); + td->td_nicename = strdup(buf); + td->td_service = t; + td->td_stop = tsdebugcw_service_destroy; + td->td_ecm_reset = tsdebugcw_ecm_reset; + LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link); +} + +/* + * + */ +void +tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even) +{ + static char empty[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + th_descrambler_t *td; + tsdebugcw_service_t *ct; + tsdebugcw_request_t *ctr; + int keylen = type == DESCRAMBLER_AES ? 16 : 8; + + LIST_FOREACH(td, &t->s_descramblers, td_service_link) + if (td->td_stop == tsdebugcw_service_destroy) + break; + if (!td) + return; + ct = (tsdebugcw_service_t *)td; + ct->tdcw_type = type; + if (memcmp(empty, odd, keylen)) + memcpy(ct->tdcw_key_odd, odd, keylen); + if (memcmp(empty, even, keylen)) + memcpy(ct->tdcw_key_even, even, keylen); + ctr = malloc(sizeof(*ctr)); + ctr->ct = ct; + pthread_mutex_lock(&tsdebugcw_mutex); + TAILQ_INSERT_TAIL(&tsdebugcw_requests, ctr, link); + pthread_mutex_unlock(&tsdebugcw_mutex); +} + +/* + * + */ +void +tsdebugcw_go(void) +{ + tsdebugcw_request_t *ctr; + tsdebugcw_service_t *ct; + + while (1) { + pthread_mutex_lock(&tsdebugcw_mutex); + ctr = TAILQ_FIRST(&tsdebugcw_requests); + if (ctr) + TAILQ_REMOVE(&tsdebugcw_requests, ctr, link); + pthread_mutex_unlock(&tsdebugcw_mutex); + if (!ctr) break; + ct = ctr->ct; + descrambler_keys((th_descrambler_t *)ct, ct->tdcw_type, + ct->tdcw_key_odd, ct->tdcw_key_even); + free(ctr); + } +} + +/* + * + */ +void +tsdebugcw_init(void) +{ + pthread_mutex_init(&tsdebugcw_mutex, NULL); + TAILQ_INIT(&tsdebugcw_requests); +} diff --git a/src/input/mpegts.h b/src/input/mpegts.h index c9676e17..a59b38b5 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -329,6 +329,12 @@ enum mpegts_mux_epg_flag }; #define MM_EPG_LAST MM_EPG_ONLY_OPENTV_SKY_AUSAT +typedef struct tsdebug_packet { + TAILQ_ENTRY(tsdebug_packet) link; + uint8_t pkt[188]; + off_t pos; +} tsdebug_packet_t; + /* Multiplex */ struct mpegts_mux { @@ -421,6 +427,16 @@ struct mpegts_mux int mm_epg; char *mm_charset; int mm_pmt_06_ac3; + + /* + * TSDEBUG + */ +#if ENABLE_TSDEBUG + int mm_tsdebug_fd; + int mm_tsdebug_fd2; + off_t mm_tsdebug_pos; + TAILQ_HEAD(, tsdebug_packet) mm_tsdebug_packets; +#endif }; /* Service */ @@ -803,6 +819,28 @@ mpegts_pid_t * mpegts_input_open_pid void mpegts_input_close_pid ( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner ); +static inline void +tsdebug_write(mpegts_mux_t *mm, uint8_t *buf, size_t len) +{ +#if ENABLE_TSDEBUG + ssize_t r = write(mm->mm_tsdebug_fd2, buf, len); + if (r != len && mm->mm_tsdebug_fd2 >= 0) + tvherror("tsdebug", "unable to write input data (%i)", errno); +#endif +} + +static inline ssize_t +sbuf_tsdebug_read(mpegts_mux_t *mm, sbuf_t *sb, int fd) +{ +#if ENABLE_TSDEBUG + ssize_t r = sbuf_read(sb, fd); + tsdebug_write(mm, sb->sb_data + sb->sb_ptr - r, r); + return r; +#else + return sbuf_read(sb, fd); +#endif +} + void mpegts_table_dispatch (const uint8_t *sec, size_t r, void *mt); static inline void mpegts_table_grab diff --git a/src/input/mpegts/iptv/iptv_http.c b/src/input/mpegts/iptv/iptv_http.c index 26c5fef8..17dbabf2 100644 --- a/src/input/mpegts/iptv/iptv_http.c +++ b/src/input/mpegts/iptv/iptv_http.c @@ -47,6 +47,7 @@ iptv_http_data pthread_mutex_lock(&iptv_lock); + tsdebug_write((mpegts_mux_t *)im, buf, len); sbuf_append(&im->mm_iptv_buffer, buf, len); if (len > 0) diff --git a/src/input/mpegts/iptv/iptv_udp.c b/src/input/mpegts/iptv/iptv_udp.c index 42ba3efa..feaa1e11 100644 --- a/src/input/mpegts/iptv/iptv_udp.c +++ b/src/input/mpegts/iptv/iptv_udp.c @@ -137,6 +137,7 @@ iptv_rtp_read ( iptv_mux_t *im ) /* Move data */ len -= hlen; + tsdebug_write((mpegts_mux_t *)im, rtp + hlen, len); sbuf_append(&im->mm_iptv_buffer, rtp + hlen, len); res += len; } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index f9d39350..c3ed43f2 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -856,7 +856,7 @@ linuxdvb_frontend_input_thread ( void *aux ) if (ev[0].data.fd != dvr) break; /* Read */ - if ((n = sbuf_read(&sb, dvr)) < 0) { + if ((n = sbuf_tsdebug_read(mmi->mmi_mux, &sb, dvr)) < 0) { if (ERRNO_AGAIN(errno)) continue; if (errno == EOVERFLOW) { diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 7b95cd1d..601e3b90 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -29,6 +29,9 @@ #include #include +#include +#include + static void mpegts_input_del_network ( mpegts_network_link_t *mnl ); @@ -475,6 +478,34 @@ static void mpegts_input_started_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi ) { +#if ENABLE_TSDEBUG + extern char *tvheadend_tsdebug; + static const char *tmpdir = "/tmp/tvheadend.tsdebug/"; + char buf[128]; + char path[PATH_MAX]; + struct stat st; + if (!tvheadend_tsdebug && !stat(tmpdir, &st) && (st.st_mode & S_IFDIR) != 0) + tvheadend_tsdebug = (char *)tmpdir; + if (tvheadend_tsdebug && !strcmp(tvheadend_tsdebug, tmpdir) && stat(tmpdir, &st)) + tvheadend_tsdebug = NULL; + if (tvheadend_tsdebug) { + mpegts_mux_nice_name(mmi->mmi_mux, buf, sizeof(buf)); + snprintf(path, sizeof(path), "%s/%s-%li-%p-mux.ts", tvheadend_tsdebug, + buf, (long)dispatch_clock, mi); + mmi->mmi_mux->mm_tsdebug_fd = tvh_open(path, O_WRONLY | O_CREAT, 0600); + if (mmi->mmi_mux->mm_tsdebug_fd < 0) + tvherror("tsdebug", "unable to create file '%s' (%i)", path, errno); + snprintf(path, sizeof(path), "%s/%s-%li-%p-input.ts", tvheadend_tsdebug, + buf, (long)dispatch_clock, mi); + mmi->mmi_mux->mm_tsdebug_fd2 = tvh_open(path, O_WRONLY | O_CREAT, 0600); + if (mmi->mmi_mux->mm_tsdebug_fd2 < 0) + tvherror("tsdebug", "unable to create file '%s' (%i)", path, errno); + } else { + mmi->mmi_mux->mm_tsdebug_fd = -1; + mmi->mmi_mux->mm_tsdebug_fd2 = -1; + } +#endif + /* Deliver first TS packets as fast as possible */ mi->mi_last_dispatch = 0; /* Wait for first TS packet */ @@ -532,6 +563,19 @@ mpegts_input_stopped_mux } notify_reload("input_status"); mpegts_input_dbus_notify(mi, 0); + +#if ENABLE_TSDEBUG + tsdebug_packet_t *tp; + close(mmi->mmi_mux->mm_tsdebug_fd); + close(mmi->mmi_mux->mm_tsdebug_fd2); + mmi->mmi_mux->mm_tsdebug_fd = -1; + mmi->mmi_mux->mm_tsdebug_fd2 = -1; + mmi->mmi_mux->mm_tsdebug_pos = 0; + while ((tp = TAILQ_FIRST(&mmi->mmi_mux->mm_tsdebug_packets)) != NULL) { + TAILQ_REMOVE(&mmi->mmi_mux->mm_tsdebug_packets, tp, link); + free(tp); + } +#endif } static int @@ -727,6 +771,37 @@ mpegts_input_table_waiting ( mpegts_input_t *mi, mpegts_mux_t *mm ) pthread_mutex_unlock(&mm->mm_tables_lock); } +#if ENABLE_TSDEBUG +static void +tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt ) +{ + void tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even); + uint32_t pos, type, keylen, sid, crc; + mpegts_service_t *t; + + if (memcmp(pkt + 4, "TVHeadendDescramblerKeys", 24)) + return; + pos = 4 + 24; + type = pkt[pos + 0]; + keylen = pkt[pos + 1]; + sid = (pkt[pos + 2] << 8) | pkt[pos + 3]; + pos += 4 + 2 * keylen; + if (pos > 184) + return; + crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) | + (pkt[pos + 2] << 8) | pkt[pos + 3]; + if (crc != tvh_crc32(pkt, pos, 0x859aa5ba)) + return; + LIST_FOREACH(t, &mm->mm_services, s_dvb_mux_link) + if (t->s_dvb_service_id == sid) break; + if (!t) + return; + pos = 4 + 24 + 4; + tvhdebug("descrambler", "Keys from MPEG-TS source (PID 0x1FFF)!"); + tsdebugcw_new_keys((service_t *)t, type, pkt + pos, pkt + pos + keylen); +} +#endif + static void mpegts_input_process ( mpegts_input_t *mi, mpegts_packet_t *mpkt ) @@ -744,6 +819,9 @@ mpegts_input_process mpegts_mux_t *mm = mpkt->mp_mux; mpegts_mux_instance_t *mmi; mpegts_pid_t *last_mp = NULL; +#if ENABLE_TSDEBUG + off_t tsdebug_pos = mm->mm_tsdebug_pos; +#endif if (mm == NULL || (mmi = mm->mm_active) == NULL) return; @@ -767,7 +845,12 @@ mpegts_input_process pid &= 0x1FFF; /* Ignore NUL packets */ - if (pid == 0x1FFF) goto done; + if (pid == 0x1FFF) { +#if ENABLE_TSDEBUG + tsdebug_check_tspkt(mm, tsb); +#endif + goto done; + } /* Remove in future or move it outside this loop */ lock_assert(&mi->mi_output_lock); @@ -841,11 +924,15 @@ mpegts_input_process done: tsb += 188; +#if ENABLE_TSDEBUG + mm->mm_tsdebug_pos += 188; +#endif } /* Raw stream */ if (tsb != mpkt->mp_data && LIST_FIRST(&mmi->mmi_streaming_pad.sp_targets) != NULL) { + streaming_message_t sm; pktbuf_t *pb = pktbuf_alloc(mpkt->mp_data, tsb - mpkt->mp_data); memset(&sm, 0, sizeof(sm)); @@ -854,6 +941,27 @@ done: streaming_pad_deliver(&mmi->mmi_streaming_pad, streaming_msg_clone(&sm)); pktbuf_ref_dec(pb); } +#if ENABLE_TSDEBUG + { + tsdebug_packet_t *tp, *tp_next; + off_t pos = 0; + size_t used = tsb - mpkt->mp_data; + for (tp = TAILQ_FIRST(&mm->mm_tsdebug_packets); tp; tp = tp_next) { + tp_next = TAILQ_NEXT(tp, link); + assert((tp->pos % 188) == 0); + assert(tp->pos >= tsdebug_pos && tp->pos < tsdebug_pos + used); + if (mm->mm_tsdebug_fd >= 0) { + tvh_write(mm->mm_tsdebug_fd, mpkt->mp_data + pos, tp->pos - tsdebug_pos - pos); + tvh_write(mm->mm_tsdebug_fd, tp->pkt, 188); + } + pos = tp->pos - tsdebug_pos; + TAILQ_REMOVE(&mm->mm_tsdebug_packets, tp, link); + free(tp); + } + if (pos < used && mm->mm_tsdebug_fd >= 0) + tvh_write(mm->mm_tsdebug_fd, mpkt->mp_data + pos, used - pos); + } +#endif /* Wake table */ if (table_wakeup) @@ -888,6 +996,14 @@ mpegts_input_thread ( void * p ) /* Cleanup */ free(mp); + +#if ENABLE_TSDEBUG + { + extern void tsdebugcw_go(void); + tsdebugcw_go(); + } +#endif + pthread_mutex_lock(&mi->mi_input_lock); } diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index c76a8fe6..d10480b8 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -1228,6 +1228,7 @@ fast_exit: (uint32_t)((uint16_t)nseq-(uint16_t)(seq+1)); seq = nseq; /* Process */ + tsdebug_write((mpegts_mux_t *)lm, p + pos, c - pos); sbuf_append(&sb, p + pos, c - pos); } mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi, diff --git a/src/input/mpegts/tsfile/tsfile_input.c b/src/input/mpegts/tsfile/tsfile_input.c index bced0a2a..f4433729 100644 --- a/src/input/mpegts/tsfile/tsfile_input.c +++ b/src/input/mpegts/tsfile/tsfile_input.c @@ -214,8 +214,8 @@ tsfile_input_start_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *t ) /* Check file is accessible */ if (lstat(mmi->mmi_tsfile_path, &st)) { - tvhlog(LOG_ERR, "tsfile", "mmi %p could not stat %s", - mmi, mmi->mmi_tsfile_path); + tvhlog(LOG_ERR, "tsfile", "mmi %p could not stat '%s' (%i)", + mmi, mmi->mmi_tsfile_path, errno); mmi->mmi_tune_failed = 1; return SM_CODE_TUNING_FAILED; } diff --git a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c index aa800878..fbe90a08 100644 --- a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c +++ b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c @@ -188,7 +188,7 @@ tvhdhomerun_frontend_input_thread ( void *aux ) if (nfds < 1) continue; if (ev[0].data.fd != sockfd) break; - if((r = sbuf_read(&sb, sockfd)) < 0) { + if((r = sbuf_tsdebug_read(mmi->mmi_mux, &sb, sockfd)) < 0) { /* whoopsy */ if(ERRNO_AGAIN(errno)) continue; diff --git a/src/main.c b/src/main.c index 3b4e8d72..c718e39f 100644 --- a/src/main.c +++ b/src/main.c @@ -132,6 +132,7 @@ int tvheadend_webui_port; int tvheadend_webui_debug; int tvheadend_htsp_port; int tvheadend_htsp_port_extra; +const char *tvheadend_tsdebug; const char *tvheadend_cwd; const char *tvheadend_webroot; const tvh_caps_t tvheadend_capabilities[] = { @@ -469,7 +470,9 @@ main(int argc, char **argv) opt_fileline = 0, opt_threadid = 0, opt_ipv6 = 0, +#if ENABLE_TSFILE opt_tsfile_tuner = 0, +#endif opt_dump = 0, opt_xspf = 0, opt_dbus = 0, @@ -560,9 +563,16 @@ main(int argc, char **argv) OPT_STR, &opt_subscribe }, +#if ENABLE_TSFILE || ENABLE_TSDEBUG { 0, NULL, "TODO: testing", OPT_BOOL, NULL }, +#if ENABLE_TSFILE { 0, "tsfile_tuners", "Number of tsfile tuners", OPT_INT, &opt_tsfile_tuner }, { 0, "tsfile", "tsfile input (mux file)", OPT_STR_LIST, &opt_tsfile }, +#endif +#if ENABLE_TSDEBUG + { 0, "tsdebug", "Output directory for tsdebug", OPT_STR, &tvheadend_tsdebug }, +#endif +#endif }; @@ -957,7 +967,9 @@ main(int argc, char **argv) if(opt_fork) unlink(opt_pidpath); +#if ENABLE_TSFILE free(opt_tsfile.str); +#endif free(opt_satip_xml.str); /* OpenSSL - welcome to the "cleanup" hell */