Merge relevant parts of PR#255 to complete the implementation of PAT/PMT passthrough, with the option of rewriting the PAT and PMT so the PAT only contains a reference to the included service, and the PMT only contains references to the included streams. This still needs more work - the PMT PID is being passed to the muxer as zero the first time a channel is streamed after tvh starts, and the PMT rewrite code fails if the PMT spans multiple TS packets

This commit is contained in:
Dave Chapman 2013-11-28 00:50:39 +00:00 committed by Adam Sutton
parent 7f11eac58a
commit 6df74d3d75
17 changed files with 213 additions and 258 deletions

View file

@ -68,6 +68,7 @@ extern struct dvr_entry_list dvrentries;
#define DVR_SKIP_COMMERCIALS 0x400
#define DVR_SUBTITLE_IN_TITLE 0x800
#define DVR_EPISODE_BEFORE_DATE 0x1000
#define DVR_REWRITE_PATPMT 0x2000
typedef enum {
DVR_PRIO_IMPORTANT,

View file

@ -1111,6 +1111,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);
@ -1307,6 +1310,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);

View file

@ -288,8 +288,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;

View file

@ -375,6 +375,7 @@ mpegts_service_create0
char buf[256];
service_create0((service_t*)s, class, uuid, S_MPEG_TS, conf);
fprintf(stderr,"Created service - pmt_pid=%d\n",pmt_pid);
/* Create */
sbuf_init(&s->s_tsbuf);
if (!conf) {

View file

@ -236,18 +236,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)

View file

@ -31,6 +31,12 @@ typedef enum {
MC_WEBM = 6,
} 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;
@ -73,7 +79,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);

View file

@ -493,7 +493,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;

View file

@ -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

View file

@ -27,17 +27,7 @@
#include "service.h"
#include "input/mpegts/dvb.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.
*/
#include "dvr/dvr.h"
typedef struct pass_muxer {
muxer_t;
@ -51,206 +41,142 @@ 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;
/**
* Append CRC
*/
static int
pass_muxer_append_crc32(uint8_t *buf, int offset, int maxlen)
static inline void set_pid_bit(uint32_t* pm_streams, uint16_t pid)
{
uint32_t crc;
if(offset + 4 > maxlen)
return -1;
crc = tvh_crc32(buf, offset, 0xffffffff);
buf[offset + 0] = crc >> 24;
buf[offset + 1] = crc >> 16;
buf[offset + 2] = crc >> 8;
buf[offset + 3] = crc;
assert(tvh_crc32(buf, offset + 4, 0xffffffff) == 0);
return offset + 4;
pm_streams[pid >> 5] |= 1 << (pid & 31);
}
/**
* PAT generator
*/
static int
pass_muxer_build_pat(service_t *t, uint8_t *buf, int maxlen, int pmtpid)
static inline int check_pid_bit(uint32_t* pm_streams, uint16_t pid)
{
if(maxlen < 12)
return -1;
buf[0] = 0;
buf[1] = 0xb0; /* reserved */
buf[2] = 12 + 4 - 3; /* Length */
buf[3] = 0x00; /* transport stream id */
buf[4] = 0x01;
buf[5] = 0xc1; /* reserved + current_next_indicator + version */
buf[6] = 0;
buf[7] = 0;
buf[8] = 0; /* Program number, we only have one program */
buf[9] = 1;
buf[10] = 0xe0 | (pmtpid >> 8);
buf[11] = pmtpid;
return pass_muxer_append_crc32(buf, 12, maxlen);
return pm_streams[pid >> 5] & (1 << (pid & 31));
}
/**
* PMT generator
/*
* 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_build_pmt(const streaming_start_t *ss, uint8_t *buf0, int maxlen,
int version, int pcrpid)
static int pass_muxer_rewrite_pat(pass_muxer_t* pm, unsigned char* buf)
{
int c, tlen, dlen, l, i;
uint8_t *buf, *buf1;
int pusi = buf[1] & 0x40;
buf = buf0;
if (pusi) {
/* First TS packet, generate our new PAT */
if(maxlen < 12)
return -1;
buf[0] = 2; /* table id, always 2 */
buf[3] = 0x00; /* program id */
buf[4] = 0x01;
buf[5] = 0xc1; /* current_next_indicator + version */
buf[5] |= (version & 0x1F) << 1;
buf[6] = 0; /* section number */
buf[7] = 0; /* last section number */
buf[8] = 0xe0 | (pcrpid >> 8);
buf[9] = pcrpid;
buf[10] = 0xf0; /* Program info length */
buf[11] = 0x00; /* We dont have any such things atm */
buf += 12;
tlen = 12;
for(i = 0; i < ss->ss_num_components; i++) {
const streaming_start_component_t *ssc = &ss->ss_components[i];
switch(ssc->ssc_type) {
case SCT_MPEG2VIDEO:
c = 0x02;
break;
case SCT_MPEG2AUDIO:
c = 0x04;
break;
case SCT_EAC3:
case SCT_DVBSUB:
c = 0x06;
break;
case SCT_MP4A:
case SCT_AAC:
c = 0x11;
break;
case SCT_H264:
c = 0x1b;
break;
case SCT_AC3:
c = 0x81;
break;
default:
continue;
/* 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;
}
buf[0] = c;
buf[1] = 0xe0 | (ssc->ssc_pid >> 8);
buf[2] = ssc->ssc_pid;
buf1 = &buf[3];
tlen += 5;
buf += 5;
dlen = 0;
switch(ssc->ssc_type) {
case SCT_MPEG2AUDIO:
case SCT_MP4A:
case SCT_AAC:
buf[0] = DVB_DESC_LANGUAGE;
buf[1] = 4;
memcpy(&buf[2],ssc->ssc_lang,3);
buf[5] = 0; /* Main audio */
dlen = 6;
break;
case SCT_DVBSUB:
buf[0] = DVB_DESC_SUBTITLE;
buf[1] = 8;
memcpy(&buf[2],ssc->ssc_lang,3);
buf[5] = 16; /* Subtitling type */
buf[6] = ssc->ssc_composition_id >> 8;
buf[7] = ssc->ssc_composition_id;
buf[8] = ssc->ssc_ancillary_id >> 8;
buf[9] = ssc->ssc_ancillary_id;
dlen = 10;
break;
case SCT_AC3:
buf[0] = DVB_DESC_LANGUAGE;
buf[1] = 4;
memcpy(&buf[2],ssc->ssc_lang,3);
buf[5] = 0; /* Main audio */
buf[6] = DVB_DESC_AC3;
buf[7] = 1;
buf[8] = 0; /* XXX: generate real AC3 desc */
dlen = 9;
break;
case SCT_EAC3:
buf[0] = DVB_DESC_LANGUAGE;
buf[1] = 4;
memcpy(&buf[2],ssc->ssc_lang,3);
buf[5] = 0; /* Main audio */
buf[6] = DVB_DESC_EAC3;
buf[7] = 1;
buf[8] = 0; /* XXX: generate real EAC3 desc */
dlen = 9;
break;
default:
break;
int current_next_indicator = (buf[10] & 0x1);
if (!current_next_indicator) {
/* If next version of PAT, do nothing */
return 0;
}
tlen += dlen;
buf += dlen;
/* 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;
buf1[0] = 0xf0 | (dlen >> 8);
buf1[1] = dlen;
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);
}
l = tlen - 3 + 4;
return 0;
}
buf0[1] = 0xb0 | (l >> 8);
buf0[2] = l;
static int pass_muxer_rewrite_pmt(pass_muxer_t* pm, unsigned char* buf)
{
int i;
return pass_muxer_append_crc32(buf0, tlen, maxlen);
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;
}
/**
@ -302,36 +228,19 @@ 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;
pm->pm_pmt_pid = ss->ss_pmt_pid;
pm->pm_service_id = ss->ss_service_id;
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(pass_muxer_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;
/* Store the PIDs of all the components */
if (pm->pm_rewrite_patpmt) {
int i;
memset(pm->pm_streams,0,1024);
for (i=0;i<ss->ss_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(pass_muxer_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;
@ -415,25 +324,33 @@ static void
pass_muxer_write_ts(muxer_t *m, pktbuf_t *pb)
{
pass_muxer_t *pm = (pass_muxer_t*)m;
int rem;
unsigned char* p;
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_pat, 188);
pass_muxer_write(m, pm->pm_pmt, 188);
pm->pm_ic++;
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);
}
@ -504,12 +421,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);
}
@ -518,7 +429,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;
@ -536,7 +447,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;
}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -43,6 +43,7 @@
#include "htsp_server.h"
#include "lang_codes.h"
#include "descrambler.h"
#include "input/mpegts.h"
static void service_data_timeout(void *aux);
static void service_class_save(struct idnode *self);
@ -846,6 +847,7 @@ service_restart(service_t *t, int had_components)
streaming_start_t *
service_build_stream_start(service_t *t)
{
extern const idclass_t mpegts_service_class;
elementary_stream_t *st;
int n = 0;
streaming_start_t *ss;
@ -881,6 +883,11 @@ 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;
if (idnode_is_instance(&t->s_id, &mpegts_service_class)) {
mpegts_service_t *ts = (mpegts_service_t*)t;
ss->ss_service_id = ts->s_dvb_service_id;
fprintf(stderr,"Streaming service %d, PMT PID is %d\n",ss->ss_service_id,ss->ss_pmt_pid);
}
return ss;
}

View file

@ -56,6 +56,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];

View file

@ -1084,6 +1084,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);
@ -1120,6 +1121,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);

View file

@ -781,6 +781,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,

View file

@ -220,7 +220,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,
th_subscription_t *s)
th_subscription_t *s, muxer_config_t *mcfg)
{
streaming_message_t *sm;
int run = 1;
@ -232,7 +232,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;
@ -663,12 +663,16 @@ http_stream_service(http_connection_t *hc, service_t *service, int weight)
size_t qsize;
const char *name;
char addrbuf[50];
muxer_config_t m_cfg;
cfg = dvr_config_find_by_name_default("");
/* 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);
@ -690,6 +694,7 @@ http_stream_service(http_connection_t *hc, service_t *service, int weight)
}
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50);
s = subscription_create_from_service(service, weight ?: 100, "HTTP", st, flags,
addrbuf,
hc->hc_username,
@ -697,7 +702,7 @@ http_stream_service(http_connection_t *hc, service_t *service, int weight)
if(s) {
name = tvh_strdupa(service->s_nicename);
pthread_mutex_unlock(&global_lock);
http_stream_run(hc, &sq, name, mc, s);
http_stream_run(hc, &sq, name, mc, s, &m_cfg);
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
}
@ -739,7 +744,7 @@ http_stream_mux(http_connection_t *hc, mpegts_mux_t *mm, int weight)
return HTTP_STATUS_BAD_REQUEST;
name = tvh_strdupa(s->ths_title);
pthread_mutex_unlock(&global_lock);
http_stream_run(hc, &sq, name, MC_RAW, s);
http_stream_run(hc, &sq, name, MC_RAW, s, NULL);
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
@ -770,12 +775,16 @@ http_stream_channel(http_connection_t *hc, channel_t *ch, int weight)
size_t qsize;
const char *name;
char addrbuf[50];
muxer_config_t m_cfg;
cfg = dvr_config_find_by_name_default("");
/* 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);
@ -813,7 +822,7 @@ http_stream_channel(http_connection_t *hc, channel_t *ch, int weight)
if(s) {
name = tvh_strdupa(channel_get_name(ch));
pthread_mutex_unlock(&global_lock);
http_stream_run(hc, &sq, name, mc, s);
http_stream_run(hc, &sq, name, mc, s, &m_cfg);
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
}