- and add skip S_DVBSUB tracks for VLC (https://trac.videolan.org/vlc/ticket/14577)
pro = de->de_config->dvr_profile;
prch = malloc(sizeof(*prch));
profile_chain_init(prch, pro, de->de_channel);
- if (profile_chain_open(prch, &de->de_config->dvr_muxcnf, 0, 0)) {
+ if (profile_chain_open(prch, &de->de_config->dvr_muxcnf, NULL, 0, 0)) {
profile_chain_close(prch);
tvherror(LS_DVR, "unable to create new channel streaming chain '%s' for '%s', using default",
profile_get_name(pro), channel_get_name(de->de_channel, channel_blank_name));
pro = profile_find_by_name(NULL, NULL);
profile_chain_init(prch, pro, de->de_channel);
- if (profile_chain_open(prch, &de->de_config->dvr_muxcnf, 0, 0)) {
+ if (profile_chain_open(prch, &de->de_config->dvr_muxcnf, NULL, 0, 0)) {
tvherror(LS_DVR, "unable to create channel streaming default chain '%s' for '%s'",
profile_get_name(pro), channel_get_name(de->de_channel, channel_blank_name));
profile_chain_close(prch);
}
if (!(muxer = prch->prch_muxer)) {
- if (profile_chain_reopen(prch, &cfg->dvr_muxcnf, 0)) {
+ if (profile_chain_reopen(prch, &cfg->dvr_muxcnf, NULL, 0)) {
dvr_rec_fatal_error(de, "Unable to reopen muxer");
return -1;
}
/**
- * Copy muxer settings
+ * Free muxer settings
*/
void
muxer_config_free(muxer_config_t *m_cfg)
}
+/**
+ * Create muxer hints
+ */
+muxer_hints_t *
+muxer_hints_create(const char *agent)
+{
+ muxer_hints_t *hints = calloc(1, sizeof(*hints));
+ mystrset(&hints->mh_agent, agent);
+ return hints;
+}
+
+
+/**
+ * Free muxer hints
+ */
+void
+muxer_hints_free(muxer_hints_t *hints)
+{
+ free(hints->mh_agent);
+ free(hints);
+}
+
+
/**
* Create a new muxer
*/
muxer_t*
-muxer_create(muxer_config_t *m_cfg)
+muxer_create(muxer_config_t *m_cfg, muxer_hints_t *hints)
{
muxer_t *m;
assert(m_cfg);
- m = pass_muxer_create(m_cfg);
+ m = pass_muxer_create(m_cfg, hints);
if(!m)
- m = mkv_muxer_create(m_cfg);
+ m = mkv_muxer_create(m_cfg, hints);
if(!m)
- m = audioes_muxer_create(m_cfg);
+ m = audioes_muxer_create(m_cfg, hints);
#if CONFIG_LIBAV
if(!m)
- m = lav_muxer_create(m_cfg);
+ m = lav_muxer_create(m_cfg, hints);
#endif
if(!m) {
tvherror(LS_MUXER, "Can't find a muxer that supports '%s' container",
muxer_container_type2txt(m_cfg->m_type));
+ muxer_hints_free(hints);
return NULL;
}
memcpy(&m->m_config, m_cfg, sizeof(muxer_config_t));
memset(m_cfg, 0, sizeof(*m_cfg));
+ m->m_hints = hints;
return m;
}
} u;
} muxer_config_t;
+typedef struct muxer_hints {
+ char *mh_agent;
+} muxer_hints_t;
+
struct muxer;
struct streaming_start;
struct th_pkt;
int m_eos; /* End of stream */
int m_errors; /* Number of errors */
muxer_config_t m_config; /* general configuration */
+ muxer_hints_t *m_hints; /* other hints */
} muxer_t;
const char* muxer_container_suffix(muxer_container_type_t mc, int video);
/* Muxer factory */
-muxer_t *muxer_create(muxer_config_t *m_cfg);
+muxer_t *muxer_create(muxer_config_t *m_cfg, muxer_hints_t *hints);
void muxer_config_copy(muxer_config_t *dst, const muxer_config_t *src);
void muxer_config_free(muxer_config_t *m_cfg);
+muxer_hints_t *muxer_hints_create(const char *agent);
+
+void muxer_hints_free(muxer_hints_t *hints);
+
/* Wrapper functions */
static inline int muxer_open_file (muxer_t *m, const char *filename)
{ if(m && filename) return m->m_open_file(m, filename); return -1; }
{ if (m) return m->m_close(m); return -1; }
static inline int muxer_destroy (muxer_t *m)
- { if (m) { m->m_destroy(m); muxer_config_free(&m->m_config); return 0; } return -1; }
+ { if (m) { m->m_destroy(m); return 0; } return -1; }
static inline int muxer_write_meta (muxer_t *m, struct epg_broadcast *eb, const char *comment)
{ if (m) return m->m_write_meta(m, eb, comment); return -1; }
if (am->am_filename)
free(am->am_filename);
+ muxer_config_free(&am->m_config);
+ muxer_hints_free(am->m_hints);
free(am);
}
* Create a new builtin muxer
*/
muxer_t*
-audioes_muxer_create(const muxer_config_t *m_cfg)
+audioes_muxer_create(const muxer_config_t *m_cfg,
+ const muxer_hints_t *hints)
{
audioes_muxer_t *am;
#include "muxer.h"
-muxer_t* audioes_muxer_create (const muxer_config_t* m_cfg);
+muxer_t *audioes_muxer_create (const muxer_config_t *m_cfg, const muxer_hints_t *hints);
#endif
lm->lm_oc = NULL;
}
+ muxer_config_free(&lm->m_config);
+ muxer_hints_free(lm->m_hints);
free(lm);
}
* Create a new libavformat based muxer
*/
muxer_t*
-lav_muxer_create(const muxer_config_t *m_cfg)
+lav_muxer_create(const muxer_config_t *m_cfg,
+ const muxer_hints_t *hints)
{
const char *mux_name;
lav_muxer_t *lm;
#include "muxer.h"
-muxer_t* lav_muxer_create (const muxer_config_t* m_cfg);
+muxer_t *lav_muxer_create (const muxer_config_t *m_cfg, const muxer_hints_t *hints);
#endif
int webm;
int dvbsub_reorder;
+ int dvbsub_skip;
struct th_pktref_queue holdq;
} mk_muxer_t;
break;
case SCT_DVBSUB:
+ if (mk->dvbsub_skip)
+ goto disable;
tracktype = 0x11;
codec_id = "S_DVBSUB";
break;
break;
default:
+disable:
ssc->ssc_muxer_disabled = 1;
tr->disabled = 1;
continue;
free(mk->filename);
free(mk->tracks);
free(mk->title);
+ muxer_config_free(&mk->m_config);
+ muxer_hints_free(mk->m_hints);
free(mk);
}
* Create a new builtin muxer
*/
muxer_t*
-mkv_muxer_create(const muxer_config_t *m_cfg)
+mkv_muxer_create(const muxer_config_t *m_cfg,
+ const muxer_hints_t *hints)
{
mk_muxer_t *mk;
+ const char *agent = hints ? hints->mh_agent : NULL;
if(m_cfg->m_type != MC_MATROSKA && m_cfg->m_type != MC_WEBM)
return NULL;
mk->dvbsub_reorder = m_cfg->u.mkv.m_dvbsub_reorder;
mk->fd = -1;
+ /*
+ * VLC has no support for MKV S_DVBSUB codec format
+ */
+ mk->dvbsub_skip = strstr(agent, "LibVLC/") != NULL;
+
TAILQ_INIT(&mk->holdq);
return (muxer_t*)mk;
#include "muxer.h"
-muxer_t* mkv_muxer_create (const muxer_config_t* m_cfg);
+muxer_t *mkv_muxer_create (const muxer_config_t *m_cfg, const muxer_hints_t *hints);
#endif /* MUXER_MKV_H_ */
dvb_table_parse_done(&pm->pm_sdt);
dvb_table_parse_done(&pm->pm_eit);
+ muxer_config_free(&pm->m_config);
+ muxer_hints_free(pm->m_hints);
free(pm);
}
* Create a new passthrough muxer
*/
muxer_t*
-pass_muxer_create(const muxer_config_t *m_cfg)
+pass_muxer_create(const muxer_config_t *m_cfg,
+ const muxer_hints_t *hints)
{
pass_muxer_t *pm;
#include "muxer.h"
-muxer_t* pass_muxer_create (const muxer_config_t* m_cfg);
+muxer_t *pass_muxer_create (const muxer_config_t *m_cfg, const muxer_hints_t *hints);
#endif
*/
int
profile_chain_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
profile_t *pro = prch->prch_pro;
if (pro && pro->pro_reopen)
- return pro->pro_reopen(prch, m_cfg, flags);
+ return pro->pro_reopen(prch, m_cfg, hints, flags);
return -1;
}
*/
int
profile_chain_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
profile_t *pro = prch->prch_pro;
if (pro && pro->pro_open)
- return pro->pro_open(prch, m_cfg, flags, qsize);
+ return pro->pro_open(prch, m_cfg, hints, flags, qsize);
return -1;
}
if (muxer) {
memset(&c, 0, sizeof(c));
c.m_type = MC_RAW;
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, NULL);
}
return 0;
}
static int
profile_mpegts_pass_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
profile_mpegts_t *pro = (profile_mpegts_t *)prch->prch_pro;
muxer_config_t c;
c.u.pass.m_rewrite_eit = pro->pro_rewrite_eit;
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_mpegts_pass_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
prch->prch_flags = SUBSCRIPTION_MPEGTS;
prch->prch_st = &prch->prch_sq.sq_st;
- profile_mpegts_pass_reopen(prch, m_cfg, flags);
- return 0;
+ return profile_mpegts_pass_reopen(prch, m_cfg, hints, flags);
}
static profile_t *
static int
profile_mpegts_spawn_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
profile_mpegts_spawn_t *pro = (profile_mpegts_spawn_t *)prch->prch_pro;
muxer_config_t c;
c.u.pass.m_killtimeout = pro->pro_killtimeout;
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_mpegts_spawn_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
prch->prch_flags = SUBSCRIPTION_MPEGTS;
prch->prch_st = &prch->prch_sq.sq_st;
- return profile_mpegts_spawn_reopen(prch, m_cfg, flags);
+ return profile_mpegts_spawn_reopen(prch, m_cfg, hints, flags);
}
static void
static int
profile_matroska_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
profile_matroska_t *pro = (profile_matroska_t *)prch->prch_pro;
muxer_config_t c;
c.u.mkv.m_dvbsub_reorder = pro->pro_dvbsub_reorder;
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_matroska_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
streaming_target_t *dst;
dst = prch->prch_tsfix = tsfix_create(dst);
prch->prch_st = dst;
- profile_matroska_reopen(prch, m_cfg, flags);
-
- return 0;
+ return profile_matroska_reopen(prch, m_cfg, hints, flags);
}
static profile_t *
static int
profile_audio_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
muxer_config_t c;
profile_audio_t *pro = (profile_audio_t *)prch->prch_pro;
c.u.audioes.m_index = pro->pro_index;
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_audio_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
int r;
return r;
}
- profile_audio_reopen(prch, m_cfg, flags);
- return 0;
+ return profile_audio_reopen(prch, m_cfg, hints, flags);
}
static profile_t *
static int
profile_libav_mpegts_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
muxer_config_t c;
c.m_type = MC_MPEGTS;
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_libav_mpegts_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
int r;
return r;
}
- profile_libav_mpegts_reopen(prch, m_cfg, flags);
- return 0;
+ return profile_libav_mpegts_reopen(prch, m_cfg, hints, flags);
}
static profile_t *
static int
profile_libav_matroska_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
profile_libav_matroska_t *pro = (profile_libav_matroska_t *)prch->prch_pro;
muxer_config_t c;
c.m_type = MC_AVWEBM;
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_libav_matroska_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
int r;
return r;
}
- profile_libav_matroska_reopen(prch, m_cfg, flags);
-
- return 0;
+ return profile_libav_matroska_reopen(prch, m_cfg, hints, flags);
}
static profile_t *
static int
profile_libav_mp4_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
muxer_config_t c;
c.m_type = MC_AVMP4;
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_libav_mp4_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
int r;
return r;
}
- profile_libav_mp4_reopen(prch, m_cfg, flags);
-
- return 0;
+ return profile_libav_mp4_reopen(prch, m_cfg, hints, flags);
}
static profile_t *
static int
profile_transcode_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags)
{
profile_transcode_t *pro = (profile_transcode_t *)prch->prch_pro;
muxer_config_t c;
}
assert(!prch->prch_muxer);
- prch->prch_muxer = muxer_create(&c);
+ prch->prch_muxer = muxer_create(&c, hints);
return 0;
}
static int
profile_transcode_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize)
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize)
{
int r;
return r;
}
- profile_transcode_reopen(prch, m_cfg, flags);
- return 0;
+ return profile_transcode_reopen(prch, m_cfg, hints, flags);
}
static void
int (*pro_work)(profile_chain_t *prch, struct streaming_target *dst,
uint32_t timeshift_period, int flags);
- int (*pro_reopen)(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags);
- int (*pro_open)(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize);
+ int (*pro_reopen)(profile_chain_t *prch, muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags);
+ int (*pro_open)(profile_chain_t *prch, muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags, size_t qsize);
} profile_t;
typedef struct profile_sharer_message {
if (--pro->pro_refcount == 0) profile_release_(pro);
}
-int
-profile_chain_work(profile_chain_t *prch, struct streaming_target *dst,
- uint32_t timeshift_period, int flags);
-int
-profile_chain_reopen(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags);
-int
-profile_chain_open(profile_chain_t *prch,
- muxer_config_t *m_cfg, int flags, size_t qsize);
+int profile_chain_work(profile_chain_t *prch, struct streaming_target *dst,
+ uint32_t timeshift_period, int flags);
+int profile_chain_reopen(profile_chain_t *prch,
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints, int flags);
+int profile_chain_open(profile_chain_t *prch,
+ muxer_config_t *m_cfg,
+ muxer_hints_t *hints,
+ int flags, size_t qsize);
void profile_chain_init(profile_chain_t *prch, profile_t *pro, void *id);
int profile_chain_raw_open(profile_chain_t *prch, void *id, size_t qsize, int muxer);
void profile_chain_close(profile_chain_t *prch);
th_subscription_t *s;
profile_t *pro;
profile_chain_t prch;
+ muxer_hints_t *hints;
const char *str;
size_t qsize;
const char *name;
else
qsize = 1500000;
+ hints = muxer_hints_create(http_arg_get(&hc->hc_args, "User-Agent"));
+
profile_chain_init(&prch, pro, service);
- if (!profile_chain_open(&prch, NULL, 0, qsize)) {
+ if (!profile_chain_open(&prch, NULL, hints, 0, qsize)) {
s = subscription_create_from_service(&prch, NULL, weight, "HTTP",
prch.prch_flags | SUBSCRIPTION_STREAMING |
th_subscription_t *s;
profile_t *pro;
profile_chain_t prch;
+ muxer_hints_t *hints;
char *str;
size_t qsize;
const char *name;
else
qsize = 1500000;
+ hints = muxer_hints_create(http_arg_get(&hc->hc_args, "User-Agent"));
+
profile_chain_init(&prch, pro, ch);
- if (!profile_chain_open(&prch, NULL, 0, qsize)) {
+ if (!profile_chain_open(&prch, NULL, hints, 0, qsize)) {
s = subscription_create_from_channel(&prch,
NULL, weight, "HTTP",