From c67bfe002bb69e5f986becd7c5e20091e0b78c16 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Sun, 24 Feb 2013 00:25:02 +0000 Subject: [PATCH 1/2] Passthrough original PAT/PMT packets to the passthrough muxer, and include these in the output stream instead of building them ourselves. A new DVR config option allows the user to specify if these are passed through unmodified, or if they are rewritten to exclude services (in the case of the PAT) or streams (in the case of the PMT) not included in the output stream. NOTE: This currently only works when the adapter is running in Full Mode - in filtered mode, no TS filters are currently set for the PAT and PMT packets, so the resulting transport stream will be missing them. --- src/dvb/dvb_adapter.c | 26 ++-- src/dvr/dvr.h | 1 + src/dvr/dvr_db.c | 4 + src/dvr/dvr_rec.c | 7 +- src/muxer.c | 8 +- src/muxer.h | 8 +- src/muxer/muxer_libav.c | 2 +- src/muxer/muxer_libav.h | 2 +- src/muxer/muxer_pass.c | 244 ++++++++++++++++++++++++++---------- src/muxer/muxer_pass.h | 2 +- src/muxer/muxer_tvh.c | 2 +- src/muxer/muxer_tvh.h | 2 +- src/service.c | 1 + src/streaming.h | 1 + src/tsdemux.c | 6 +- src/webui/extjs.c | 4 + src/webui/static/app/dvr.js | 3 + src/webui/webui.c | 122 +++++------------- 18 files changed, 263 insertions(+), 182 deletions(-) diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index 861c111788..cc177deff1 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -1083,21 +1083,21 @@ dvb_adapter_input_dvr(void *aux) /* sync */ if (tsb[i] == 0x47) { - int pid = (tsb[i+1] & 0x1f) << 8 | tsb[i+2]; - - if(tda->tda_table_filter[pid]) { - if(!(tsb[i+1] & 0x80)) { // Only dispatch to table parser if not error - dvb_table_feed_t *dtf = malloc(sizeof(dvb_table_feed_t)); - memcpy(dtf->dtf_tsb, tsb + i, 188); - TAILQ_INSERT_TAIL(&tda->tda_table_feed, dtf, dtf_link); - wakeup_table_feed = 1; - } - } else { - LIST_FOREACH(t, &tda->tda_transports, s_active_link) - if(t->s_dvb_mux_instance == tda->tda_mux_current) - ts_recv_packet1(t, tsb + i, NULL); + int pid = (tsb[i+1] & 0x1f) << 8 | tsb[i+2]; + + if(tda->tda_table_filter[pid]) { + if(!(tsb[i+1] & 0x80)) { // Only dispatch to table parser if not error + dvb_table_feed_t *dtf = malloc(sizeof(dvb_table_feed_t)); + memcpy(dtf->dtf_tsb, tsb + i, 188); + TAILQ_INSERT_TAIL(&tda->tda_table_feed, dtf, dtf_link); + wakeup_table_feed = 1; + } } + LIST_FOREACH(t, &tda->tda_transports, s_active_link) + if(t->s_dvb_mux_instance == tda->tda_mux_current) + ts_recv_packet1(t, tsb + i, NULL); + i += 188; r -= 188; diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 4bc56aa754..bf5e575b58 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -66,6 +66,7 @@ extern struct dvr_entry_list dvrentries; #define DVR_CLEAN_TITLE 0x100 #define DVR_TAG_FILES 0x200 #define DVR_SKIP_COMMERCIALS 0x400 +#define DVR_REWRITE_PATPMT 0x800 typedef enum { DVR_PRIO_IMPORTANT, diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index d9cfe026c5..cfe49f4b33 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -994,6 +994,9 @@ dvr_init(void) cfg->dvr_mc = htsmsg_get_u32_or_default(m, "container", MC_MATROSKA); + if(!htsmsg_get_u32(m, "rewrite-patpmt", &u32) && u32) + cfg->dvr_flags |= DVR_REWRITE_PATPMT; + htsmsg_get_s32(m, "pre-extra-time", &cfg->dvr_extra_time_pre); htsmsg_get_s32(m, "post-extra-time", &cfg->dvr_extra_time_post); htsmsg_get_u32(m, "retention-days", &cfg->dvr_retention_days); @@ -1182,6 +1185,7 @@ dvr_save(dvr_config_t *cfg) htsmsg_add_str(m, "config_name", cfg->dvr_config_name); htsmsg_add_str(m, "storage", cfg->dvr_storage); htsmsg_add_u32(m, "container", cfg->dvr_mc); + htsmsg_add_u32(m, "rewrite-patpmt", !!(cfg->dvr_flags & DVR_REWRITE_PATPMT)); htsmsg_add_u32(m, "retention-days", cfg->dvr_retention_days); htsmsg_add_u32(m, "pre-extra-time", cfg->dvr_extra_time_pre); htsmsg_add_u32(m, "post-extra-time", cfg->dvr_extra_time_post); diff --git a/src/dvr/dvr_rec.c b/src/dvr/dvr_rec.c index c48eafff2a..0f3a1f60f3 100644 --- a/src/dvr/dvr_rec.c +++ b/src/dvr/dvr_rec.c @@ -287,8 +287,13 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss) const streaming_start_component_t *ssc; int i; dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name); + muxer_container_type_t mc; + muxer_config_t m_cfg; - de->de_mux = muxer_create(de->de_mc); + mc = de->de_mc; + m_cfg.rewrite_patpmt = !!(cfg->dvr_flags & DVR_REWRITE_PATPMT); + + de->de_mux = muxer_create(mc, &m_cfg); if(!de->de_mux) { dvr_rec_fatal_error(de, "Unable to create muxer"); return -1; diff --git a/src/muxer.c b/src/muxer.c index e252a53b69..5a604d08cf 100644 --- a/src/muxer.c +++ b/src/muxer.c @@ -231,18 +231,18 @@ muxer_container_mime2type(const char *str) * Create a new muxer */ muxer_t* -muxer_create(muxer_container_type_t mc) +muxer_create(muxer_container_type_t mc, muxer_config_t *m_cfg) { muxer_t *m; - m = pass_muxer_create(mc); + m = pass_muxer_create(mc, m_cfg); if(!m) - m = tvh_muxer_create(mc); + m = tvh_muxer_create(mc, m_cfg); #if CONFIG_LIBAV if(!m) - m = lav_muxer_create(mc); + m = lav_muxer_create(mc, m_cfg); #endif if(!m) diff --git a/src/muxer.h b/src/muxer.h index 1cfc947aff..2294316df4 100644 --- a/src/muxer.h +++ b/src/muxer.h @@ -30,6 +30,12 @@ typedef enum { MC_RAW = 5, } muxer_container_type_t; +/* Muxer configuration used when creating a muxer. */ +typedef struct muxer_config { + /* Options only for passthrough muxer */ + int rewrite_patpmt; + +} muxer_config_t; struct muxer; struct streaming_start; @@ -72,7 +78,7 @@ const char* muxer_container_suffix(muxer_container_type_t mc, int vid int muxer_container_list(htsmsg_t *array); // Muxer factory -muxer_t *muxer_create(muxer_container_type_t mc); +muxer_t *muxer_create(muxer_container_type_t mc, muxer_config_t *m_cfg); // Wrapper functions int muxer_open_file (muxer_t *m, const char *filename); diff --git a/src/muxer/muxer_libav.c b/src/muxer/muxer_libav.c index 7837afe6c5..d237da5221 100644 --- a/src/muxer/muxer_libav.c +++ b/src/muxer/muxer_libav.c @@ -467,7 +467,7 @@ lav_muxer_destroy(muxer_t *m) * Create a new libavformat based muxer */ muxer_t* -lav_muxer_create(muxer_container_type_t mc) +lav_muxer_create(muxer_container_type_t mc, muxer_config_t *m_cfg) { const char *mux_name; lav_muxer_t *lm; diff --git a/src/muxer/muxer_libav.h b/src/muxer/muxer_libav.h index a8325b062e..748898b3c0 100644 --- a/src/muxer/muxer_libav.h +++ b/src/muxer/muxer_libav.h @@ -21,6 +21,6 @@ #include "muxer.h" -muxer_t* lav_muxer_create(muxer_container_type_t mc); +muxer_t* lav_muxer_create(muxer_container_type_t mc, muxer_config_t* m_cfg); #endif diff --git a/src/muxer/muxer_pass.c b/src/muxer/muxer_pass.c index 50dd5e2333..6eb5804119 100644 --- a/src/muxer/muxer_pass.c +++ b/src/muxer/muxer_pass.c @@ -25,18 +25,9 @@ #include "streaming.h" #include "epg.h" #include "psi.h" +#include "dvr/dvr.h" #include "muxer_pass.h" -#define TS_INJECTION_RATE 1000 - -/* -TODO: How often do we send the injected packets? - Once evry packet? Once every 1000 packets? - Or perhaps even once 10k packets? - Maby we should messure in seconds instead? - For now, every 1000 packets will do. -*/ - typedef struct pass_muxer { muxer_t; @@ -49,14 +40,143 @@ typedef struct pass_muxer { char *pm_filename; /* TS muxing */ - uint8_t pm_injection; - uint8_t *pm_pat; - uint8_t *pm_pmt; - uint16_t pm_pmt_version; - uint32_t pm_ic; // Injection counter - uint32_t pm_pc; // Packet counter + uint8_t pm_rewrite_patpmt; + uint8_t pm_pat_cc; + uint16_t pm_pmt_pid; + uint16_t pm_service_id; + uint32_t pm_streams[256]; /* lookup table identifying which streams to include in the PMT */ } pass_muxer_t; +static inline void set_pid_bit(uint32_t* pm_streams, uint16_t pid) +{ + pm_streams[pid >> 5] |= 1 << (pid & 31); +} + +static inline int check_pid_bit(uint32_t* pm_streams, uint16_t pid) +{ + return pm_streams[pid >> 5] & (1 << (pid & 31)); +} + +/* + * Rewrite a PAT packet to only include the service included in the transport stream. + * + * This is complicated by the need to deal with PATs that span more than one transport + * stream packet. In that scenario, we replace the 2nd and subsequent PAT packets with + * NULL packets (PID 0x1fff). + * + */ + +static int pass_muxer_rewrite_pat(pass_muxer_t* pm, unsigned char* buf) +{ + int pusi = buf[1] & 0x40; + + if (pusi) { + /* First TS packet, generate our new PAT */ + + /* Some sanity checks */ + if (buf[4] != 0) { + tvhlog(LOG_ERR, "pass", "Unsupported PAT format - pointer_to_data != 0 (%d) (Please report to developers!)\n",buf[4]); + return 1; + } + int last_section_number = buf[12]; + if (last_section_number != 0) { + tvhlog(LOG_ERR, "pass", "Multi-section PAT not supported (last_section_number = %d) (Please report to developers!)\n",last_section_number); + return 2; + } + + int current_next_indicator = (buf[10] & 0x1); + if (!current_next_indicator) { + /* If next version of PAT, do nothing */ + return 0; + } + + /* Rewrite continuity counter, in case this is a multi-packet PAT (we discard all but the first packet) */ + buf[3] = (buf[3] & 0xf0) | pm->pm_pat_cc; + pm->pm_pat_cc = (pm->pm_pat_cc + 1) & 0xf; + + buf[6] = 0; buf[7] = 13; /* section_length (number of bytes after this field, including CRC) */ + + buf[13] = (pm->pm_service_id & 0xff00) >> 8; + buf[14] = pm->pm_service_id & 0x00ff; + buf[15] = 0xe0 | ((pm->pm_pmt_pid & 0x1f00) >> 8); + buf[16] = pm->pm_pmt_pid & 0x00ff; + + uint32_t crc32 = tvh_crc32(buf+5, 12, 0xffffffff); + buf[17] = (crc32 & 0xff000000) >> 24; + buf[18] = (crc32 & 0x00ff0000) >> 16; + buf[19] = (crc32 & 0x0000ff00) >> 8; + buf[20] = crc32 & 0x000000ff; + + memset(buf + 21, 0xff, 167); /* Wipe rest of packet */ + } else { + /* The second or subsequent packet of a multi-packet PAT, replace with NULL packet */ + buf[1] = 0x1f; /* pid 0x1fff */ + memset(buf+2, 0xff, 186); + } + + return 0; +} + +static int pass_muxer_rewrite_pmt(pass_muxer_t* pm, unsigned char* buf) +{ + int i; + + int pusi = buf[1] & 0x40; + + if (pusi) { + /* First TS packet, generate our new PAT */ + + int current_next_indicator = (buf[10] & 0x1); + if (!current_next_indicator) { + /* If next version of PAT, do nothing */ + return 0; + } + + /* Some sanity checks */ + if (buf[4] != 0) { + tvhlog(LOG_ERR, "pass", "Unsupported PMT format - pointer_to_data != 0 (%d) (Please report to developers!)\n",buf[4]); + return 1; + } + int last_section_number = buf[12]; + if (last_section_number != 0) { + tvhlog(LOG_ERR, "pass", "Multi-section PMT not supported (last_section_number = %d) (Please report to developers!)\n",last_section_number); + return 2; + } + + int section_length = ((buf[6]&0x0f) << 8) | buf[7]; i += 2; + if (section_length > (188 - 4 - 7)) { /* 7 bytes before section_length, plus CRC */ + tvhlog(LOG_ERR, "pass", "Multi-packet PMT not supported (last_section_number = %d) (Please report to developers!)\n",last_section_number); + } + + i = 15; + + int program_info_length = ((buf[i] & 0x0f) << 8) | buf[i+1]; i += 2; + i += program_info_length; + + while ( i < 7 + section_length - 4) { + //int stream_type = buf[i]; + int pid = ((buf[i+1]&0x1f) << 8) | buf[i+2]; + int ES_info_length = ((buf[i+3] & 0x0f) << 8) | buf[i+4]; + + if (check_pid_bit(pm->pm_streams,pid)) { + i += 5 + ES_info_length; + } else { + memmove(buf + i, buf + i + 5 + ES_info_length,(188-i-5-ES_info_length)); + section_length -= (5+ES_info_length); + } + } + + buf[7] = section_length; + + uint32_t crc32 = tvh_crc32(buf+5, i-5, 0xffffffff); + buf[i++] = ((crc32 & 0xff000000) >> 24); + buf[i++] = ((crc32 & 0x00ff0000) >> 16); + buf[i++] = ((crc32 & 0x0000ff00) >> 8); + buf[i++] = (crc32 & 0x000000ff); + } + + return 0; +} /** * Figure out the mime-type for the muxed data stream @@ -107,38 +227,21 @@ static int pass_muxer_reconfigure(muxer_t* m, const struct streaming_start *ss) { pass_muxer_t *pm = (pass_muxer_t*)m; - const source_info_t *si = &ss->ss_si; - if(si->si_type == S_MPEG_TS && ss->ss_pmt_pid) { - pm->pm_pat = realloc(pm->pm_pat, 188); - memset(pm->pm_pat, 0xff, 188); - pm->pm_pat[0] = 0x47; - pm->pm_pat[1] = 0x40; - pm->pm_pat[2] = 0x00; - pm->pm_pat[3] = 0x10; - pm->pm_pat[4] = 0x00; - if(psi_build_pat(NULL, pm->pm_pat+5, 183, ss->ss_pmt_pid) < 0) { - pm->m_errors++; - tvhlog(LOG_ERR, "pass", "%s: Unable to build pat", pm->pm_filename); - return -1; + pm->pm_pmt_pid = ss->ss_pmt_pid; + pm->pm_service_id = ss->ss_service_id; + + /* Store the PIDs of all the components */ + if (pm->pm_rewrite_patpmt) { + int i; + memset(pm->pm_streams,0,1024); + for (i=0;iss_num_components;i++) { + /* SCT_TEXTSUB (text extracted from teletext) streams are virtual and have an invalid PID */ + if (ss->ss_components[i].ssc_pid < 8192) { + set_pid_bit(pm->pm_streams,ss->ss_components[i].ssc_pid); + } } - - pm->pm_pmt = realloc(pm->pm_pmt, 188); - memset(pm->pm_pmt, 0xff, 188); - pm->pm_pmt[0] = 0x47; - pm->pm_pmt[1] = 0x40 | (ss->ss_pmt_pid >> 8); - pm->pm_pmt[2] = 0x00 | (ss->ss_pmt_pid >> 0); - pm->pm_pmt[3] = 0x10; - pm->pm_pmt[4] = 0x00; - if(psi_build_pmt(ss, pm->pm_pmt+5, 183, pm->pm_pmt_version, - ss->ss_pcr_pid) < 0) { - pm->m_errors++; - tvhlog(LOG_ERR, "pass", "%s: Unable to build pmt", pm->pm_filename); - return -1; - } - pm->pm_pmt_version++; } - return 0; } @@ -220,25 +323,33 @@ static void pass_muxer_write_ts(muxer_t *m, pktbuf_t *pb) { pass_muxer_t *pm = (pass_muxer_t*)m; - int rem; - - if(pm->pm_pat != NULL && - pm->pm_pmt != NULL && - pm->pm_injection) { - // Inject pmt and pat into the stream - rem = pm->pm_pc % TS_INJECTION_RATE; - if(!rem) { - pm->pm_pat[3] = (pm->pm_pat[3] & 0xf0) | (pm->pm_ic & 0x0f); - pm->pm_pmt[3] = (pm->pm_pmt[3] & 0xf0) | (pm->pm_ic & 0x0f); - pass_muxer_write(m, pm->pm_pmt, 188); - pass_muxer_write(m, pm->pm_pat, 188); - pm->pm_ic++; + unsigned char* p; + + if (pm->pm_rewrite_patpmt) { + p = pb->pb_data; + while (p < pb->pb_data + pb->pb_size) { + int pid = (p[1] & 0x1f) << 8 | p[2]; + + if (pid == 0) { + /* Remove all PMT references except the one being streamed */ + if (pass_muxer_rewrite_pat(pm, p)) { + tvhlog(LOG_ERR, "pass", "Error rewriting PAT, sending original\n"); + pm->pm_rewrite_patpmt = 0; /* There was an error, so just give user original PAT from now on */ + break; + } + } else if (pid == pm->pm_pmt_pid) { + /* Remove all references to streams not being streamed */ + if (pass_muxer_rewrite_pmt(pm, p)) { + tvhlog(LOG_ERR, "pass", "Error rewriting PMT, sending original\n"); + pm->pm_rewrite_patpmt = 0; /* There was an error, so just give user original PMT from now on */ + break; + } + } + p += 188; } } pass_muxer_write(m, pb->pb_data, pb->pb_size); - - pm->pm_pc += (pb->pb_size / 188); } @@ -309,12 +420,6 @@ pass_muxer_destroy(muxer_t *m) if(pm->pm_filename) free(pm->pm_filename); - if(pm->pm_pmt) - free(pm->pm_pmt); - - if(pm->pm_pat) - free(pm->pm_pat); - free(pm); } @@ -323,7 +428,7 @@ pass_muxer_destroy(muxer_t *m) * Create a new passthrough muxer */ muxer_t* -pass_muxer_create(muxer_container_type_t mc) +pass_muxer_create(muxer_container_type_t mc, muxer_config_t *m_cfg) { pass_muxer_t *pm; @@ -341,7 +446,10 @@ pass_muxer_create(muxer_container_type_t mc) pm->m_close = pass_muxer_close; pm->m_destroy = pass_muxer_destroy; pm->pm_fd = -1; - pm->pm_injection = (mc == MC_PASS); + /* Copy any configuration values we are interested in */ + if ((mc == MC_PASS) && (m_cfg)) { + pm->pm_rewrite_patpmt = m_cfg->rewrite_patpmt; + } return (muxer_t *)pm; } diff --git a/src/muxer/muxer_pass.h b/src/muxer/muxer_pass.h index 919c210429..e93495a2a6 100644 --- a/src/muxer/muxer_pass.h +++ b/src/muxer/muxer_pass.h @@ -21,6 +21,6 @@ #include "muxer.h" -muxer_t* pass_muxer_create(muxer_container_type_t mc); +muxer_t* pass_muxer_create(muxer_container_type_t mc, muxer_config_t* m_cfg); #endif diff --git a/src/muxer/muxer_tvh.c b/src/muxer/muxer_tvh.c index 6d46b91245..df684cb9f6 100644 --- a/src/muxer/muxer_tvh.c +++ b/src/muxer/muxer_tvh.c @@ -220,7 +220,7 @@ tvh_muxer_destroy(muxer_t *m) * Create a new builtin muxer */ muxer_t* -tvh_muxer_create(muxer_container_type_t mc) +tvh_muxer_create(muxer_container_type_t mc, muxer_config_t *m_cfg) { tvh_muxer_t *tm; diff --git a/src/muxer/muxer_tvh.h b/src/muxer/muxer_tvh.h index 143429dcc3..384b566875 100644 --- a/src/muxer/muxer_tvh.h +++ b/src/muxer/muxer_tvh.h @@ -21,6 +21,6 @@ #include "muxer.h" -muxer_t* tvh_muxer_create(muxer_container_type_t mc); +muxer_t* tvh_muxer_create(muxer_container_type_t mc, muxer_config_t* m_cfg); #endif diff --git a/src/service.c b/src/service.c index 2bf84aa20a..73260e937f 100644 --- a/src/service.c +++ b/src/service.c @@ -921,6 +921,7 @@ service_build_stream_start(service_t *t) ss->ss_refcount = 1; ss->ss_pcr_pid = t->s_pcr_pid; ss->ss_pmt_pid = t->s_pmt_pid; + ss->ss_service_id = t->s_dvb_service_id; return ss; } diff --git a/src/streaming.h b/src/streaming.h index 75dc7857a7..75385db0b6 100644 --- a/src/streaming.h +++ b/src/streaming.h @@ -55,6 +55,7 @@ typedef struct streaming_start { uint16_t ss_pcr_pid; uint16_t ss_pmt_pid; + uint16_t ss_service_id; streaming_start_component_t ss_components[0]; diff --git a/src/tsdemux.c b/src/tsdemux.c index 69b9237402..103ff7e24f 100644 --- a/src/tsdemux.c +++ b/src/tsdemux.c @@ -76,6 +76,10 @@ ts_recv_packet0(service_t *t, elementary_stream_t *st, const uint8_t *tsb) if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS)) ts_remux(t, tsb); + /* If this was a PAT/PMT packet, st is NULL, so we do no more */ + if (!st) + return; + error = !!(tsb[1] & 0x80); pusi = !!(tsb[1] & 0x40); @@ -211,7 +215,7 @@ ts_recv_packet1(service_t *t, const uint8_t *tsb, int64_t *pcrp) if(tsb[3] & 0x20 && tsb[4] > 0 && tsb[5] & 0x10 && !error) ts_extract_pcr(t, st, tsb, pcrp); - if(st == NULL) { + if((st == NULL) && (pid != 0) && (pid != t->s_pmt_pid)) { pthread_mutex_unlock(&t->s_stream_mutex); return; } diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 4d365f81b2..1a26ba4cf5 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -1245,6 +1245,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) r = htsmsg_create_map(); htsmsg_add_str(r, "storage", cfg->dvr_storage); htsmsg_add_str(r, "container", muxer_container_type2txt(cfg->dvr_mc)); + htsmsg_add_u32(r, "rewritePATPMT", !!(cfg->dvr_flags & DVR_REWRITE_PATPMT)); if(cfg->dvr_postproc != NULL) htsmsg_add_str(r, "postproc", cfg->dvr_postproc); htsmsg_add_u32(r, "retention", cfg->dvr_retention_days); @@ -1279,6 +1280,9 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) if((s = http_arg_get(&hc->hc_req_args, "container")) != NULL) dvr_container_set(cfg,s); + if(http_arg_get(&hc->hc_req_args, "rewritePATPMT") != NULL) + flags |= DVR_REWRITE_PATPMT; + if((s = http_arg_get(&hc->hc_req_args, "postproc")) != NULL) dvr_postproc_set(cfg,s); diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js index 02021eb3b8..259d1a5041 100644 --- a/src/webui/static/app/dvr.js +++ b/src/webui/static/app/dvr.js @@ -775,6 +775,9 @@ tvheadend.dvrsettings = function() { editable : false, width : 200, hiddenName : 'container' + }), new Ext.form.Checkbox({ + fieldLabel : 'Rewrite PAT/PMT in passthrough mode', + name : 'rewritePATPMT' }), new Ext.form.NumberField({ allowNegative : false, allowDecimals : false, diff --git a/src/webui/webui.c b/src/webui/webui.c index bc7d5989ee..fc740cb86a 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -156,7 +156,7 @@ page_static_file(http_connection_t *hc, const char *remain, void *opaque) */ static void http_stream_run(http_connection_t *hc, streaming_queue_t *sq, - const char *name, muxer_container_type_t mc) + const char *name, muxer_container_type_t mc, muxer_config_t *mcfg) { streaming_message_t *sm; int run = 1; @@ -168,7 +168,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, int err = 0; socklen_t errlen = sizeof(err); - mux = muxer_create(mc); + mux = muxer_create(mc, mcfg); if(muxer_open_stream(mux, hc->hc_fd)) run = 0; @@ -549,29 +549,32 @@ page_http_playlist(http_connection_t *hc, const char *remain, void *opaque) /** - * Subscribes to a service and starts the streaming loop + * Subscribes to a channel or service and starts the streaming loop */ static int -http_stream_service(http_connection_t *hc, service_t *service) +http_stream_channel_or_service(http_connection_t *hc, channel_t *ch, service_t *service) { streaming_queue_t sq; th_subscription_t *s; streaming_target_t *gh; streaming_target_t *tsfix; streaming_target_t *st; - dvr_config_t *cfg; + dvr_config_t *cfg = dvr_config_find_by_name_default("");; muxer_container_type_t mc; + int priority = 100; int flags; const char *str; size_t qsize; const char *name; char addrbuf[50]; + muxer_config_t m_cfg; + /* Build muxer config - this takes the defaults from the default dvr config, which is a hack */ mc = muxer_container_txt2type(http_arg_get(&hc->hc_req_args, "mux")); if(mc == MC_UNKNOWN) { - cfg = dvr_config_find_by_name_default(""); mc = cfg->dvr_mc; } + m_cfg.rewrite_patpmt = !!(cfg->dvr_flags & DVR_REWRITE_PATPMT); if ((str = http_arg_get(&hc->hc_req_args, "qsize"))) qsize = atoll(str); @@ -593,15 +596,28 @@ http_stream_service(http_connection_t *hc, service_t *service) } tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50); - s = subscription_create_from_service(service, "HTTP", st, flags, - addrbuf, - hc->hc_username, - http_arg_get(&hc->hc_args, "User-Agent")); - if(s) { - name = strdupa(service->s_ch ? - service->s_ch->ch_name : service->s_nicename); + if (service) { + s = subscription_create_from_service(service, "HTTP", st, flags, + addrbuf, + hc->hc_username, + http_arg_get(&hc->hc_args, "User-Agent")); + } else { + s = subscription_create_from_channel(ch, priority, "HTTP", st, flags, + addrbuf, + hc->hc_username, + http_arg_get(&hc->hc_args, "User-Agent")); + } + + if (s) { + if (service) { + name = strdupa(service->s_ch ? + service->s_ch->ch_name : service->s_nicename); + } else { + name = strdupa(ch->ch_name); + } + pthread_mutex_unlock(&global_lock); - http_stream_run(hc, &sq, name, mc); + http_stream_run(hc, &sq, name, mc, &m_cfg); pthread_mutex_lock(&global_lock); subscription_unsubscribe(s); } @@ -638,7 +654,7 @@ http_stream_tdmi(http_connection_t *hc, th_dvb_mux_instance_t *tdmi) http_arg_get(&hc->hc_args, "User-Agent")); name = strdupa(tdmi->tdmi_identifier); pthread_mutex_unlock(&global_lock); - http_stream_run(hc, &sq, name, MC_RAW); + http_stream_run(hc, &sq, name, MC_RAW, NULL); pthread_mutex_lock(&global_lock); subscription_unsubscribe(s); @@ -649,76 +665,6 @@ http_stream_tdmi(http_connection_t *hc, th_dvb_mux_instance_t *tdmi) #endif -/** - * Subscribes to a channel and starts the streaming loop - */ -static int -http_stream_channel(http_connection_t *hc, channel_t *ch) -{ - streaming_queue_t sq; - th_subscription_t *s; - streaming_target_t *gh; - streaming_target_t *tsfix; - streaming_target_t *st; - dvr_config_t *cfg; - int priority = 100; - int flags; - muxer_container_type_t mc; - char *str; - size_t qsize; - const char *name; - char addrbuf[50]; - - mc = muxer_container_txt2type(http_arg_get(&hc->hc_req_args, "mux")); - if(mc == MC_UNKNOWN) { - cfg = dvr_config_find_by_name_default(""); - mc = cfg->dvr_mc; - } - - if ((str = http_arg_get(&hc->hc_req_args, "qsize"))) - qsize = atoll(str); - else - qsize = 1500000; - - if(mc == MC_PASS || mc == MC_RAW) { - streaming_queue_init2(&sq, SMT_PACKET, qsize); - gh = NULL; - tsfix = NULL; - st = &sq.sq_st; - flags = SUBSCRIPTION_RAW_MPEGTS; - } else { - streaming_queue_init2(&sq, 0, qsize); - gh = globalheaders_create(&sq.sq_st); - tsfix = tsfix_create(gh); - st = tsfix; - flags = 0; - } - - tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50); - s = subscription_create_from_channel(ch, priority, "HTTP", st, flags, - addrbuf, - hc->hc_username, - http_arg_get(&hc->hc_args, "User-Agent")); - - if(s) { - name = strdupa(ch->ch_name); - pthread_mutex_unlock(&global_lock); - http_stream_run(hc, &sq, name, mc); - pthread_mutex_lock(&global_lock); - subscription_unsubscribe(s); - } - - if(gh) - globalheaders_destroy(gh); - if(tsfix) - tsfix_destroy(tsfix); - - streaming_queue_deinit(&sq); - - return 0; -} - - /** * Handle the http request. http://tvheadend/stream/channelid/ * http://tvheadend/stream/channel/ @@ -763,10 +709,8 @@ http_stream(http_connection_t *hc, const char *remain, void *opaque) #endif } - if(ch != NULL) { - return http_stream_channel(hc, ch); - } else if(service != NULL) { - return http_stream_service(hc, service); + if ((ch != NULL) || (service != NULL)) { + return http_stream_channel_or_service(hc, ch, service); #if ENABLE_LINUXDVB } else if(tdmi != NULL) { return http_stream_tdmi(hc, tdmi); From 0eeb66df6868186627896269428919dff80230f7 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Thu, 28 Feb 2013 14:18:27 +0000 Subject: [PATCH 2/2] Fix for scrambled streams - st is NULL for PAT/PMT streams, which are never scrambled. --- src/tsdemux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tsdemux.c b/src/tsdemux.c index 103ff7e24f..49c1db9ba9 100644 --- a/src/tsdemux.c +++ b/src/tsdemux.c @@ -226,7 +226,7 @@ ts_recv_packet1(service_t *t, const uint8_t *tsb, int64_t *pcrp) avgstat_add(&t->s_rate, 188, dispatch_clock); if((tsb[3] & 0xc0) || - (t->s_scrambled_seen && st->es_type != SCT_CA && + (t->s_scrambled_seen && st && st->es_type != SCT_CA && st->es_type != SCT_PMT)) { /**