From f104564aa1f281655daf0fdf57d76c5426df3750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Mon, 5 Mar 2012 15:53:14 +0100 Subject: [PATCH 01/10] Use channel name as title of stream and set the programme name as a tag named TITLE --- src/dvr/mkmux.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index 85c3f233..6aea66fb 100644 --- a/src/dvr/mkmux.c +++ b/src/dvr/mkmux.c @@ -551,6 +551,9 @@ mk_build_metadata2(const event_t *e) if(e->e_channel != NULL) addtag(q, build_tag_string("TVCHANNEL", e->e_channel->ch_name, 0, NULL)); + if(e->e_title != NULL) + addtag(q, build_tag_string("TITLE", e->e_title, 0, NULL)); + if(e->e_episode.ee_onscreen) addtag(q, build_tag_string("SYNOPSIS", e->e_episode.ee_onscreen, 0, NULL)); @@ -740,7 +743,12 @@ mk_mux_stream_create(int fd, const struct streaming_start *ss, getuuid(mkm->uuid); mkm->filename = strdup("Live stream"); mkm->fd = fd; - mkm->title = strdup(e ? e->e_title : mkm->filename); + + if(e && e->e_channel && e->e_channel->ch_name) + mkm->title = strdup(e->e_channel->ch_name); + else + mkm->title = strdup("Live stream"); + TAILQ_INIT(&mkm->cues); htsbuf_queue_init(&q, 0); From 54f7b758018a8a375893a293869a1697939d9369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Mon, 5 Mar 2012 15:55:41 +0100 Subject: [PATCH 02/10] increased initial 'tuning' timeout for http from 5 seconds to 20 seconds --- src/webui/webui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webui/webui.c b/src/webui/webui.c index 1862e6e3..5eeedbf7 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -155,8 +155,8 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t //Check socket status getsockopt(hc->hc_fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen); - //Abort upon socket error, or after 5 seconds of silence - if(err || timeouts > 4){ + //Abort upon socket error, or after 20 seconds of silence + if(err || timeouts >= 20){ run = 0; } } From ea617c8e24f2e748b892120340e22dc35a0fc8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Mon, 5 Mar 2012 17:34:10 +0100 Subject: [PATCH 03/10] fix offset for metainfo when metatags are present. not sure how these values add up but mkvalidator claims they are correct --- src/dvr/mkmux.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index 6aea66fb..6b42f008 100644 --- a/src/dvr/mkmux.c +++ b/src/dvr/mkmux.c @@ -664,15 +664,16 @@ mk_build_segment(mk_mux_t *mkm, htsbuf_queue_t q; htsbuf_queue_t *p = htsbuf_queue_alloc(0); htsbuf_queue_init(&q, 0); - - mkm->segmentinfo_pos = 33; + int offset = e ? 48 : 33; + + mkm->segmentinfo_pos = offset; ebml_append_master(&q, 0x1549a966, mk_build_segment_info(mkm)); - mkm->trackinfo_pos = 33 + q.hq_size; + mkm->trackinfo_pos = offset + q.hq_size; ebml_append_master(&q, 0x1654ae6b, mk_build_tracks(mkm, ss)); if(e) { - mkm->metadata_pos = 33 + q.hq_size; + mkm->metadata_pos = offset + q.hq_size; ebml_append_master(&q, 0x1254c367, mk_build_metadata2(e)); } From 839b164d7b080dfc796f27419c7884cb03b8cdf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Mon, 5 Mar 2012 17:34:38 +0100 Subject: [PATCH 04/10] Add meta tags to webstream --- src/webui/webui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webui/webui.c b/src/webui/webui.c index 5eeedbf7..267507ec 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -183,7 +183,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t else http_output_content(hc, "video/x-matroska"); - event_t *e = NULL; //epg_event_find_by_time(s->ths_channel, dispatch_clock); + event_t *e = s->ths_channel->ch_epg_current; mkm = mk_mux_stream_create(hc->hc_fd, sm->sm_data, e); break; From 115089def3b34915466b2d6fe2d3b3cdfea1a90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Mon, 5 Mar 2012 17:51:52 +0100 Subject: [PATCH 05/10] Log when a http streams starts and stops --- src/webui/webui.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webui/webui.c b/src/webui/webui.c index 267507ec..58ea8e00 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -178,6 +178,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t break; case SMT_START: { + tvhlog(LOG_DEBUG, "webui", "Start streaming %s", hc->hc_url_orig); if(s->ths_service->s_servicetype == ST_RADIO) http_output_content(hc, "audio/x-matroska"); else @@ -196,6 +197,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t break; case SMT_NOSTART: + tvhlog(LOG_DEBUG, "webui", "Couldn't start stream for %s", hc->hc_url_orig); run = 0; break; From 3cea8ad970c72848a5a86459940721539c9c9308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Mon, 5 Mar 2012 17:52:38 +0100 Subject: [PATCH 06/10] Check for null pointers --- src/webui/webui.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/webui/webui.c b/src/webui/webui.c index 58ea8e00..b8d16fb7 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -178,13 +178,16 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t break; case SMT_START: { + event_t *e = NULL; tvhlog(LOG_DEBUG, "webui", "Start streaming %s", hc->hc_url_orig); + if(s->ths_service->s_servicetype == ST_RADIO) http_output_content(hc, "audio/x-matroska"); else http_output_content(hc, "video/x-matroska"); - event_t *e = s->ths_channel->ch_epg_current; + if(s->ths_channel) + e = s->ths_channel->ch_epg_current; mkm = mk_mux_stream_create(hc->hc_fd, sm->sm_data, e); break; From e6826dca0ef22c79ade31c1f91c9c92fe4ba47a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Tue, 6 Mar 2012 13:57:45 +0100 Subject: [PATCH 07/10] Made the maximum cluster size smaller for live streams and even smaller for live audio only streams --- src/dvr/mkmux.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index 6b42f008..2fdc97bc 100644 --- a/src/dvr/mkmux.c +++ b/src/dvr/mkmux.c @@ -79,7 +79,7 @@ struct mk_mux { htsbuf_queue_t *cluster; int64_t cluster_tc; off_t cluster_pos; - + int cluster_maxsize; off_t segment_header_pos; @@ -706,6 +706,7 @@ mk_mux_create(const char *filename, mkm->filename = strdup(filename); mkm->fd = fd; mkm->title = strdup(de->de_title); + mkm->cluster_maxsize = 2*1024*1024; //2Mb TAILQ_INIT(&mkm->cues); mk_write_master(mkm, 0x1a45dfa3, mk_build_ebmlheader()); @@ -760,6 +761,11 @@ mk_mux_stream_create(int fd, const struct streaming_start *ss, mk_write_queue(mkm, &q); + if(mkm->has_video) + mkm->cluster_maxsize = 100*1024; //200Kb + else + mkm->cluster_maxsize = 10*1024; //20Kb + return mkm; } @@ -804,7 +810,6 @@ mk_write_frame_i(mk_mux_t *mkm, mk_track *t, th_pkt_t *pkt) uint8_t *data; size_t len; - const int clusersizemax = 2000000; if(pts == PTS_UNSET) // This is our best guess, it might be wrong but... oh well @@ -830,13 +835,10 @@ mk_write_frame_i(mk_mux_t *mkm, mk_track *t, th_pkt_t *pkt) return; } - if(vkeyframe && mkm->cluster && mkm->cluster->hq_size > clusersizemax/4) + if(vkeyframe && mkm->cluster && mkm->cluster->hq_size > mkm->cluster_maxsize / 4) mk_close_cluster(mkm); - else if(mkm->cluster && mkm->cluster->hq_size > clusersizemax) - mk_close_cluster(mkm); - - else if(!mkm->has_video && mkm->cluster && mkm->cluster->hq_size > clusersizemax/40) + else if(mkm->cluster && mkm->cluster->hq_size > mkm->cluster_maxsize) mk_close_cluster(mkm); if(mkm->cluster == NULL) { From 6e02f496bf3f8468a1f4ac8bfc1d3d0f02dffc56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Tue, 6 Mar 2012 14:48:10 +0100 Subject: [PATCH 08/10] for streaming, use the smallest possible cluster size (one cluster per keyframe). --- src/dvr/mkmux.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index 2fdc97bc..8e5ceec8 100644 --- a/src/dvr/mkmux.c +++ b/src/dvr/mkmux.c @@ -706,7 +706,7 @@ mk_mux_create(const char *filename, mkm->filename = strdup(filename); mkm->fd = fd; mkm->title = strdup(de->de_title); - mkm->cluster_maxsize = 2*1024*1024; //2Mb + mkm->cluster_maxsize = 2000000/4; TAILQ_INIT(&mkm->cues); mk_write_master(mkm, 0x1a45dfa3, mk_build_ebmlheader()); @@ -745,6 +745,7 @@ mk_mux_stream_create(int fd, const struct streaming_start *ss, getuuid(mkm->uuid); mkm->filename = strdup("Live stream"); mkm->fd = fd; + mkm->cluster_maxsize = 0; if(e && e->e_channel && e->e_channel->ch_name) mkm->title = strdup(e->e_channel->ch_name); @@ -761,11 +762,6 @@ mk_mux_stream_create(int fd, const struct streaming_start *ss, mk_write_queue(mkm, &q); - if(mkm->has_video) - mkm->cluster_maxsize = 100*1024; //200Kb - else - mkm->cluster_maxsize = 10*1024; //20Kb - return mkm; } @@ -810,6 +806,7 @@ mk_write_frame_i(mk_mux_t *mkm, mk_track *t, th_pkt_t *pkt) uint8_t *data; size_t len; + const int clusersizemax = 2000000; if(pts == PTS_UNSET) // This is our best guess, it might be wrong but... oh well @@ -835,10 +832,13 @@ mk_write_frame_i(mk_mux_t *mkm, mk_track *t, th_pkt_t *pkt) return; } - if(vkeyframe && mkm->cluster && mkm->cluster->hq_size > mkm->cluster_maxsize / 4) + if(vkeyframe && mkm->cluster && mkm->cluster->hq_size > mkm->cluster_maxsize) mk_close_cluster(mkm); - else if(mkm->cluster && mkm->cluster->hq_size > mkm->cluster_maxsize) + else if(!mkm->has_video && mkm->cluster && mkm->cluster->hq_size > clusersizemax/40) + mk_close_cluster(mkm); + + else if(mkm->cluster && mkm->cluster->hq_size > clusersizemax) mk_close_cluster(mkm); if(mkm->cluster == NULL) { From 19ad4c12628a36d9e1d786bbcb5f7794313d8a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Tue, 6 Mar 2012 14:48:58 +0100 Subject: [PATCH 09/10] avoid calling lseek on sockets as a socket is not seekable. --- src/dvr/mkmux.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index 8e5ceec8..270040d1 100644 --- a/src/dvr/mkmux.c +++ b/src/dvr/mkmux.c @@ -69,6 +69,7 @@ struct mk_mux { char *filename; int error; off_t fdpos; // Current position in file + int seekable; mk_track *tracks; int ntracks; @@ -638,7 +639,7 @@ mk_write_metaseek(mk_mux_t *mkm, int first) if(first) { mk_write_to_fd(mkm, &q); - } else { + } else if(mkm->seekable) { off_t prev = mkm->fdpos; if(lseek(mkm->fd, mkm->segment_pos, SEEK_SET) == (off_t) -1) mkm->error = errno; @@ -707,6 +708,7 @@ mk_mux_create(const char *filename, mkm->fd = fd; mkm->title = strdup(de->de_title); mkm->cluster_maxsize = 2000000/4; + mkm->seekable = 1; TAILQ_INIT(&mkm->cues); mk_write_master(mkm, 0x1a45dfa3, mk_build_ebmlheader()); @@ -958,19 +960,21 @@ mk_mux_close(mk_mux_t *mkm) mk_write_metaseek(mkm, 0); totsize = mkm->fdpos; - // Rewrite segment info to update duration - if(lseek(mkm->fd, mkm->segmentinfo_pos, SEEK_SET) == mkm->segmentinfo_pos) - mk_write_master(mkm, 0x1549a966, mk_build_segment_info(mkm)); - else - tvhlog(LOG_ERR, "MKV", "%s: Unable to write duration, seek failed -- %s", - mkm->filename, strerror(errno)); + if(mkm->seekable) { + // Rewrite segment info to update duration + if(lseek(mkm->fd, mkm->segmentinfo_pos, SEEK_SET) == mkm->segmentinfo_pos) + mk_write_master(mkm, 0x1549a966, mk_build_segment_info(mkm)); + else + tvhlog(LOG_ERR, "MKV", "%s: Unable to write duration, seek failed -- %s", + mkm->filename, strerror(errno)); - // Rewrite segment header to update total size - if(lseek(mkm->fd, mkm->segment_header_pos, SEEK_SET) == mkm->segment_header_pos) { - mk_write_segment_header(mkm, totsize - mkm->segment_header_pos - 12); - } else - tvhlog(LOG_ERR, "MKV", "%s: Unable to write total size, seek failed -- %s", - mkm->filename, strerror(errno)); + // Rewrite segment header to update total size + if(lseek(mkm->fd, mkm->segment_header_pos, SEEK_SET) == mkm->segment_header_pos) { + mk_write_segment_header(mkm, totsize - mkm->segment_header_pos - 12); + } else + tvhlog(LOG_ERR, "MKV", "%s: Unable to write total size, seek failed -- %s", + mkm->filename, strerror(errno)); + } close(mkm->fd); free(mkm->filename); From 841ab9087f62d77c685d76c76fd083597791b8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Tue, 6 Mar 2012 18:07:49 +0100 Subject: [PATCH 10/10] skip seekhead for live streams and append epg tags whenever they change. --- src/dvr/mkmux.c | 48 +++++++++++++++++++++++++---------------------- src/dvr/mkmux.h | 6 +++++- src/webui/webui.c | 19 +++++++++++++------ 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index 270040d1..54a350ce 100644 --- a/src/dvr/mkmux.c +++ b/src/dvr/mkmux.c @@ -659,28 +659,15 @@ mk_write_metaseek(mk_mux_t *mkm, int first) */ static htsbuf_queue_t * mk_build_segment(mk_mux_t *mkm, - const struct streaming_start *ss, - const event_t *e) + const struct streaming_start *ss) { - htsbuf_queue_t q; htsbuf_queue_t *p = htsbuf_queue_alloc(0); - htsbuf_queue_init(&q, 0); - int offset = e ? 48 : 33; - mkm->segmentinfo_pos = offset; - ebml_append_master(&q, 0x1549a966, mk_build_segment_info(mkm)); + mkm->segmentinfo_pos = p->hq_size; + ebml_append_master(p, 0x1549a966, mk_build_segment_info(mkm)); - mkm->trackinfo_pos = offset + q.hq_size; - ebml_append_master(&q, 0x1654ae6b, mk_build_tracks(mkm, ss)); - - if(e) { - mkm->metadata_pos = offset + q.hq_size; - ebml_append_master(&q, 0x1254c367, mk_build_metadata2(e)); - } - - ebml_append_master(p, 0x114d9b74, mk_build_metaseek(mkm)); - htsbuf_appendq(p, &q); - htsbuf_queue_flush(&q); + mkm->trackinfo_pos = p->hq_size; + ebml_append_master(p, 0x1654ae6b, mk_build_tracks(mkm, ss)); return p; } @@ -738,7 +725,7 @@ mk_mux_create(const char *filename, mk_mux_t * mk_mux_stream_create(int fd, const struct streaming_start *ss, - const event_t *e) + const channel_t *ch) { mk_mux_t *mkm; htsbuf_queue_t q; @@ -749,8 +736,8 @@ mk_mux_stream_create(int fd, const struct streaming_start *ss, mkm->fd = fd; mkm->cluster_maxsize = 0; - if(e && e->e_channel && e->e_channel->ch_name) - mkm->title = strdup(e->e_channel->ch_name); + if(ch && ch->ch_name) + mkm->title = strdup(ch->ch_name); else mkm->title = strdup("Live stream"); @@ -760,13 +747,14 @@ mk_mux_stream_create(int fd, const struct streaming_start *ss, ebml_append_master(&q, 0x1a45dfa3, mk_build_ebmlheader()); htsbuf_appendq(&q, mk_build_segment_header(0)); - htsbuf_appendq(&q, mk_build_segment(mkm, ss, e)); + htsbuf_appendq(&q, mk_build_segment(mkm, ss)); mk_write_queue(mkm, &q); return mkm; } + /** * */ @@ -793,6 +781,22 @@ mk_close_cluster(mk_mux_t *mkm) } +/** + * + */ +int +mk_mux_append_meta(mk_mux_t *mkm, event_t *e) +{ + htsbuf_queue_t q; + + htsbuf_queue_init(&q, 0); + ebml_append_master(&q, 0x1254c367, mk_build_metadata2(e)); + mk_write_queue(mkm, &q); + + return mkm->error; +} + + /** * */ diff --git a/src/dvr/mkmux.h b/src/dvr/mkmux.h index fb5d94ab..f0304351 100644 --- a/src/dvr/mkmux.h +++ b/src/dvr/mkmux.h @@ -24,6 +24,8 @@ typedef struct mk_mux mk_mux_t; struct streaming_start; struct dvr_entry; struct th_pkt; +struct channel; +struct event; mk_mux_t *mk_mux_create(const char *filename, const struct streaming_start *ss, @@ -32,10 +34,12 @@ mk_mux_t *mk_mux_create(const char *filename, mk_mux_t *mk_mux_stream_create(int fd, const struct streaming_start *ss, - const event_t *e); + const struct channel *ch); int mk_mux_write_pkt(mk_mux_t *mkm, struct th_pkt *pkt); +int mk_mux_append_meta(mk_mux_t *mkm, struct event *e); + void mk_mux_close(mk_mux_t *mk_mux); #endif // MKMUX_H__ diff --git a/src/webui/webui.c b/src/webui/webui.c index b8d16fb7..ed69ebdf 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -133,6 +133,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t streaming_message_t *sm; int run = 1; mk_mux_t *mkm = NULL; + uint32_t event_id = 0; int timeouts = 0; while(run) { @@ -168,17 +169,26 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t TAILQ_REMOVE(&sq->sq_queue, sm, sm_link); switch(sm->sm_type) { - case SMT_PACKET: + case SMT_PACKET: { if(!mkm) break; pkt_ref_inc(sm->sm_data); run = !mk_mux_write_pkt(mkm, sm->sm_data); sm->sm_data = NULL; + + event_t *e = NULL; + if(s->ths_channel) + e = s->ths_channel->ch_epg_current; + + if(e && event_id != e->e_id) { + event_id = e->e_id; + run = !mk_mux_append_meta(mkm, e); + } break; + } case SMT_START: { - event_t *e = NULL; tvhlog(LOG_DEBUG, "webui", "Start streaming %s", hc->hc_url_orig); if(s->ths_service->s_servicetype == ST_RADIO) @@ -186,10 +196,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t else http_output_content(hc, "video/x-matroska"); - if(s->ths_channel) - e = s->ths_channel->ch_epg_current; - - mkm = mk_mux_stream_create(hc->hc_fd, sm->sm_data, e); + mkm = mk_mux_stream_create(hc->hc_fd, sm->sm_data, s->ths_channel); break; } case SMT_STOP: