diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index 85c3f233..54a350ce 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; @@ -79,7 +80,7 @@ struct mk_mux { htsbuf_queue_t *cluster; int64_t cluster_tc; off_t cluster_pos; - + int cluster_maxsize; off_t segment_header_pos; @@ -551,6 +552,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)); @@ -635,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; @@ -655,27 +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); + + mkm->segmentinfo_pos = p->hq_size; + ebml_append_master(p, 0x1549a966, mk_build_segment_info(mkm)); - mkm->segmentinfo_pos = 33; - ebml_append_master(&q, 0x1549a966, mk_build_segment_info(mkm)); - - mkm->trackinfo_pos = 33 + q.hq_size; - ebml_append_master(&q, 0x1654ae6b, mk_build_tracks(mkm, ss)); - - if(e) { - mkm->metadata_pos = 33 + 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; } @@ -702,6 +694,8 @@ mk_mux_create(const char *filename, mkm->filename = strdup(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()); @@ -731,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; @@ -740,20 +734,27 @@ 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); + mkm->cluster_maxsize = 0; + + if(ch && ch->ch_name) + mkm->title = strdup(ch->ch_name); + else + mkm->title = strdup("Live stream"); + TAILQ_INIT(&mkm->cues); htsbuf_queue_init(&q, 0); 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; } + /** * */ @@ -780,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; +} + + /** * */ @@ -821,15 +838,15 @@ 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) - mk_close_cluster(mkm); - - else if(mkm->cluster && mkm->cluster->hq_size > clusersizemax) + if(vkeyframe && mkm->cluster && mkm->cluster->hq_size > mkm->cluster_maxsize) mk_close_cluster(mkm); 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) { mkm->cluster_tc = pts; mkm->cluster = htsbuf_queue_alloc(0); @@ -947,19 +964,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); 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 1862e6e3..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) { @@ -155,8 +156,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; } } @@ -168,24 +169,34 @@ 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: { + 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 = NULL; //epg_event_find_by_time(s->ths_channel, dispatch_clock); - - 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: @@ -196,6 +207,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;