From 92409b644efb18d3359a17f27f7f34c4b89c0177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Wed, 17 Sep 2008 20:54:37 +0000 Subject: [PATCH] Implement a lose interface for streaming internally in tvheadend. --- Makefile | 2 +- cwc.c | 24 +++++++-- dvb/dvb_adapter.c | 8 +-- dvb/dvb_transport.c | 10 +++- packet.h | 1 + parsers.c | 14 +++--- psi.c | 66 +++++++++++++------------ streaming.c | 30 ++++++++++++ streaming.h | 34 +++++++++++++ transports.c | 59 +++++++++++++++-------- transports.h | 19 +++++++- tsdemux.c | 32 ++++-------- tvhead.h | 115 +++++++++++++++++++++++++++++++++----------- webui/extjs.c | 30 +++++++----- 14 files changed, 313 insertions(+), 131 deletions(-) create mode 100644 streaming.c create mode 100644 streaming.h diff --git a/Makefile b/Makefile index 0774e482..45c39718 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SRCS = main.c access.c dtable.c tcp.c http.c notify.c epg.c xmltv.c spawn.c -SRCS += packet.c +SRCS += packet.c streaming.c VPATH += dvr SRCS += dvr_db.c diff --git a/cwc.c b/cwc.c index 044971a9..be2553ed 100644 --- a/cwc.c +++ b/cwc.c @@ -888,6 +888,24 @@ cwc_transport_destroy(th_descrambler_t *td) free(ct); } +/** + * + */ +static inline th_stream_t * +cwc_find_stream_by_caid(th_transport_t *t, int caid) +{ + streaming_pad_t *sp = &t->tht_streaming_pad; + th_stream_t *st; + streaming_component_t *sc; + + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; + if(st->st_caid == caid) + return st; + } + return NULL; +} + /** * Check if our CAID's matches, and if so, link @@ -908,11 +926,7 @@ cwc_transport_start(th_transport_t *t) if(cwc->cwc_caid == 0) continue; - LIST_FOREACH(st, &t->tht_streams, st_link) - if(st->st_caid == cwc->cwc_caid) - break; - - if(st == NULL) + if((st = cwc_find_stream_by_caid(t, cwc->cwc_caid)) == NULL) continue; ct = calloc(1, sizeof(cwc_transport_t)); diff --git a/dvb/dvb_adapter.c b/dvb/dvb_adapter.c index d81aafe5..1305a400 100644 --- a/dvb/dvb_adapter.c +++ b/dvb/dvb_adapter.c @@ -393,6 +393,7 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src) th_dvb_mux_instance_t *tdmi_src, *tdmi_dst; th_transport_t *t_src, *t_dst; th_stream_t *st_src, *st_dst; + streaming_component_t *sc_src; lock_assert(&global_lock); @@ -437,15 +438,16 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src) pthread_mutex_lock(&t_src->tht_stream_mutex); - LIST_FOREACH(st_src, &t_src->tht_streams, st_link) { + LIST_FOREACH(sc_src, &t_src->tht_streaming_pad.sp_components, sc_link) { + st_src = (th_stream_t *)sc_src; st_dst = transport_add_stream(t_dst, st_src->st_pid, - st_src->st_type); + st_src->st_sc.sc_type); st_dst->st_tb = (AVRational){1, 90000}; - memcpy(st_dst->st_lang, st_src->st_lang, 4); + memcpy(st_dst->st_sc.sc_lang, st_src->st_sc.sc_lang, 4); st_dst->st_frame_duration = st_src->st_frame_duration; st_dst->st_caid = st_src->st_caid; } diff --git a/dvb/dvb_transport.c b/dvb/dvb_transport.c index bda9c8b0..5a18cd35 100644 --- a/dvb/dvb_transport.c +++ b/dvb/dvb_transport.c @@ -57,6 +57,8 @@ static int dvb_transport_start(th_transport_t *t, unsigned int weight, int status, int force_start) { + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; struct dmx_pes_filter_params dmx_param; th_stream_t *st; int w, fd, pid; @@ -86,7 +88,8 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int status, } tdmi = t->tht_dvb_mux_instance; - LIST_FOREACH(st, &t->tht_streams, st_link) { + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; fd = open(tda->tda_demux_path, O_RDWR); @@ -139,6 +142,8 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int status, static void dvb_transport_stop(th_transport_t *t) { + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; th_dvb_adapter_t *tda = t->tht_dvb_mux_instance->tdmi_adapter; th_stream_t *st; @@ -148,7 +153,8 @@ dvb_transport_stop(th_transport_t *t) LIST_REMOVE(t, tht_active_link); pthread_mutex_unlock(&tda->tda_delivery_mutex); - LIST_FOREACH(st, &t->tht_streams, st_link) { + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; close(st->st_demuxer_fd); st->st_demuxer_fd = -1; } diff --git a/packet.h b/packet.h index 8e909a8f..48c2df4e 100644 --- a/packet.h +++ b/packet.h @@ -33,6 +33,7 @@ typedef struct th_pkt { int pkt_duration; int pkt_refcount; + uint8_t pkt_streamindex; uint8_t pkt_frametype; uint8_t pkt_commercial; diff --git a/parsers.c b/parsers.c index ad9d9172..6abf8908 100644 --- a/parsers.c +++ b/parsers.c @@ -117,20 +117,20 @@ parse_raw_mpeg(th_transport_t *t, th_stream_t *st, uint8_t *data, } - switch(st->st_type) { - case HTSTV_MPEG2VIDEO: + switch(st->st_sc.sc_type) { + case SCT_MPEG2VIDEO: parse_video(t, st, data, len, parse_mpeg2video); break; - case HTSTV_H264: + case SCT_H264: parse_video(t, st, data, len, parse_h264); break; - case HTSTV_MPEG2AUDIO: + case SCT_MPEG2AUDIO: parse_audio(t, st, data, len, start, parse_mpegaudio); break; - case HTSTV_AC3: + case SCT_AC3: parse_audio(t, st, data, len, start, parse_ac3); break; @@ -897,8 +897,8 @@ parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt) /* Per stream type analysis */ - switch(st->st_type) { - case HTSTV_MPEG2VIDEO: + switch(st->st_sc.sc_type) { + case SCT_MPEG2VIDEO: for(i = 0; i < pkt->pkt_payloadlen && err == 0; i++) { sc = (sc << 8) | buf[i]; diff --git a/psi.c b/psi.c index 0459585f..9ef11977 100644 --- a/psi.c +++ b/psi.c @@ -92,7 +92,7 @@ psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len, pid = (ptr[2] & 0x1f) << 8 | ptr[3]; if(prognum != 0) { - st = transport_add_stream(t, pid, HTSTV_PMT); + st = transport_add_stream(t, pid, SCT_PMT); st->st_section_docrc = 1; st->st_got_section = pmt_callback; @@ -177,7 +177,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) int dllen; uint8_t dtag, dlen; uint16_t sid; - tv_streamtype_t hts_stream_type; + streaming_component_type_t hts_stream_type; th_stream_t *st; char lang[4]; int frameduration; @@ -208,7 +208,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) switch(dtag) { case DVB_DESC_CA: - st = transport_add_stream(t, (ptr[2] & 0x1f) << 8 | ptr[3], HTSTV_CA); + st = transport_add_stream(t, (ptr[2] & 0x1f) << 8 | ptr[3], SCT_CA); st->st_caid = (ptr[0] << 8) | ptr[1]; break; @@ -233,17 +233,17 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) switch(estype) { case 0x01: case 0x02: - hts_stream_type = HTSTV_MPEG2VIDEO; + hts_stream_type = SCT_MPEG2VIDEO; break; case 0x03: case 0x04: case 0x81: - hts_stream_type = HTSTV_MPEG2AUDIO; + hts_stream_type = SCT_MPEG2AUDIO; break; case 0x1b: - hts_stream_type = HTSTV_H264; + hts_stream_type = SCT_H264; break; } @@ -268,12 +268,12 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) case DVB_DESC_TELETEXT: if(estype == 0x06) - hts_stream_type = HTSTV_TELETEXT; + hts_stream_type = SCT_TELETEXT; break; case DVB_DESC_AC3: if(estype == 0x06 || estype == 0x81) - hts_stream_type = HTSTV_AC3; + hts_stream_type = SCT_AC3; break; default: @@ -285,7 +285,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) if(hts_stream_type != 0) { st = transport_add_stream(t, pid, hts_stream_type); st->st_tb = (AVRational){1, 90000}; - memcpy(st->st_lang, lang, 4); + memcpy(st->st_sc.sc_lang, lang, 4); if(st->st_frame_duration == 0) st->st_frame_duration = frameduration; @@ -346,19 +346,19 @@ psi_build_pmt(th_muxer_t *tm, uint8_t *buf0, int maxlen, int pcrpid) continue; switch(st->st_type) { - case HTSTV_MPEG2VIDEO: + case SCT_MPEG2VIDEO: c = 0x02; break; - case HTSTV_MPEG2AUDIO: + case SCT_MPEG2AUDIO: c = 0x03; break; - case HTSTV_H264: + case SCT_H264: c = 0x1b; break; - case HTSTV_AC3: + case SCT_AC3: c = 0x06; break; @@ -377,7 +377,7 @@ psi_build_pmt(th_muxer_t *tm, uint8_t *buf0, int maxlen, int pcrpid) dlen = 0; switch(st->st_type) { - case HTSTV_AC3: + case SCT_AC3: buf[0] = DVB_DESC_AC3; buf[1] = 1; buf[2] = 0; /* XXX: generate real AC3 desc */ @@ -525,15 +525,15 @@ psi_caid2name(uint16_t caid) * */ static struct strtab streamtypetab[] = { - { "MPEG2VIDEO", HTSTV_MPEG2VIDEO }, - { "MPEG2AUDIO", HTSTV_MPEG2AUDIO }, - { "H264", HTSTV_H264 }, - { "AC3", HTSTV_AC3 }, - { "TELETEXT", HTSTV_TELETEXT }, - { "SUBTITLES", HTSTV_SUBTITLES }, - { "CA", HTSTV_CA }, - { "PMT", HTSTV_PMT }, - { "PAT", HTSTV_PAT }, + { "MPEG2VIDEO", SCT_MPEG2VIDEO }, + { "MPEG2AUDIO", SCT_MPEG2AUDIO }, + { "H264", SCT_H264 }, + { "AC3", SCT_AC3 }, + { "TELETEXT", SCT_TELETEXT }, + { "SUBTITLES", SCT_SUBTITLES }, + { "CA", SCT_CA }, + { "PMT", SCT_PMT }, + { "PAT", SCT_PAT }, }; @@ -543,7 +543,7 @@ static struct strtab streamtypetab[] = { const char * -htstvstreamtype2txt(tv_streamtype_t s) +streaming_component_type2txt(streaming_component_type_t s) { return val2str(s, streamtypetab) ?: "INVALID"; } @@ -555,6 +555,8 @@ htstvstreamtype2txt(tv_streamtype_t s) void psi_save_transport_settings(htsmsg_t *m, th_transport_t *t) { + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; th_stream_t *st; htsmsg_t *sub; @@ -564,16 +566,18 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t) lock_assert(&t->tht_stream_mutex); - LIST_FOREACH(st, &t->tht_streams, st_link) { + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; + sub = htsmsg_create(); htsmsg_add_u32(sub, "pid", st->st_pid); - htsmsg_add_str(sub, "type", val2str(st->st_type, streamtypetab) ?: "?"); + htsmsg_add_str(sub, "type", val2str(sc->sc_type, streamtypetab) ?: "?"); - if(st->st_lang[0]) - htsmsg_add_str(sub, "language", st->st_lang); + if(sc->sc_lang[0]) + htsmsg_add_str(sub, "language", sc->sc_lang); - if(st->st_type == HTSTV_CA) + if(sc->sc_type == SCT_CA) htsmsg_add_str(sub, "caid", psi_caid2name(st->st_caid)); if(st->st_frame_duration) @@ -594,7 +598,7 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t) htsmsg_field_t *f; uint32_t u32; th_stream_t *st; - tv_streamtype_t type; + streaming_component_type_t type; const char *v; uint32_t pid, i; @@ -625,7 +629,7 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t) st->st_tb = (AVRational){1, 90000}; if((v = htsmsg_get_str(c, "language")) != NULL) - av_strlcpy(st->st_lang, v, 4); + av_strlcpy(st->st_sc.sc_lang, v, 4); if(!htsmsg_get_u32(c, "frameduration", &u32)) st->st_frame_duration = u32; diff --git a/streaming.c b/streaming.c new file mode 100644 index 00000000..616bccd9 --- /dev/null +++ b/streaming.c @@ -0,0 +1,30 @@ +/** + * Streaming helpers + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "tvhead.h" +#include "streaming.h" + +void +streaming_pad_init(streaming_pad_t *sp, pthread_mutex_t *mutex) +{ + LIST_INIT(&sp->sp_targets); + LIST_INIT(&sp->sp_components); + sp->sp_mutex = mutex; +} diff --git a/streaming.h b/streaming.h new file mode 100644 index 00000000..35f95ed3 --- /dev/null +++ b/streaming.h @@ -0,0 +1,34 @@ +/* + * Stream plumbing, connects individual streaming components to each other + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef STREAMING_H_ +#define STREAMING_H_ + +#include "tvhead.h" + + +/** + * + */ +void streaming_pad_init(streaming_pad_t *pd, pthread_mutex_t *mutex); + +void streaming_taget_init(streaming_target_t *st); + +void streaming_target_connect(streaming_pad_t *pd, streaming_target_t *st); + +#endif /* STREAMING_H_ */ diff --git a/transports.c b/transports.c index ba20c565..71f34cce 100644 --- a/transports.c +++ b/transports.c @@ -35,7 +35,7 @@ #include "transports.h" #include "subscriptions.h" #include "tsdemux.h" - +#include "streaming.h" #include "v4l.h" #include "psi.h" #include "packet.h" @@ -62,6 +62,9 @@ static void transport_data_timeout(void *aux); static void transport_stop(th_transport_t *t) { + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; + th_descrambler_t *td; th_stream_t *st; @@ -84,7 +87,8 @@ transport_stop(th_transport_t *t) /** * Clean up each stream */ - LIST_FOREACH(st, &t->tht_streams, st_link) { + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; if(st->st_parser != NULL) av_parser_close(st->st_parser); @@ -208,6 +212,9 @@ transport_unlink_muxer(th_muxer_t *tm) int transport_start(th_transport_t *t, unsigned int weight, int force_start) { + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; + th_stream_t *st; AVCodec *c; enum CodecID id; @@ -221,7 +228,12 @@ transport_start(th_transport_t *t, unsigned int weight, int force_start) t->tht_dts_start = AV_NOPTS_VALUE; t->tht_pcr_drift = 0; - LIST_FOREACH(st, &t->tht_streams, st_link) { + + /** + * Initialize stream + */ + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; st->st_startcond = 0xffffffff; st->st_curdts = AV_NOPTS_VALUE; @@ -237,11 +249,11 @@ transport_start(th_transport_t *t, unsigned int weight, int force_start) st->st_pcr_recovery_fails = 0; /* Open ffmpeg context and parser */ - switch(st->st_type) { - case HTSTV_MPEG2VIDEO: id = CODEC_ID_MPEG2VIDEO; break; - case HTSTV_MPEG2AUDIO: id = CODEC_ID_MP3; break; - case HTSTV_H264: id = CODEC_ID_H264; break; - case HTSTV_AC3: id = CODEC_ID_AC3; break; + switch(sc->sc_type) { + case SCT_MPEG2VIDEO: id = CODEC_ID_MPEG2VIDEO; break; + case SCT_MPEG2AUDIO: id = CODEC_ID_MP3; break; + case SCT_H264: id = CODEC_ID_H264; break; + case SCT_AC3: id = CODEC_ID_AC3; break; default: id = CODEC_ID_NONE; break; } @@ -424,7 +436,8 @@ transport_data_timeout(void *aux, int64_t now) void transport_destroy(th_transport_t *t) { - th_stream_t *st; + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; th_subscription_t *s; lock_assert(&global_lock); @@ -453,9 +466,9 @@ transport_destroy(th_transport_t *t) free(t->tht_chname); free(t->tht_provider); - while((st = LIST_FIRST(&t->tht_streams)) != NULL) { - LIST_REMOVE(st, st_link); - free(st); + while((sc = LIST_FIRST(&sp->sp_components)) != NULL) { + LIST_REMOVE(sc, sc_link); + free(sc); } abort();// serviceprobe_delete(t); @@ -476,11 +489,12 @@ transport_create(const char *identifier, int type, int source_type) lock_assert(&global_lock); pthread_mutex_init(&t->tht_stream_mutex, NULL); - pthread_cond_init(&t->tht_stream_cond, NULL); t->tht_identifier = strdup(identifier); t->tht_type = type; t->tht_source_type = source_type; + streaming_pad_init(&t->tht_streaming_pad, &t->tht_stream_mutex); + LIST_INSERT_HEAD(&transporthash[hash], t, tht_hash_link); return t; } @@ -510,25 +524,31 @@ transport_find_by_identifier(const char *identifier) * */ th_stream_t * -transport_add_stream(th_transport_t *t, int pid, tv_streamtype_t type) +transport_add_stream(th_transport_t *t, int pid, + streaming_component_type_t type) { + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; th_stream_t *st; int i = 0; lock_assert(&t->tht_stream_mutex); - LIST_FOREACH(st, &t->tht_streams, st_link) { + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; i++; if(pid != -1 && st->st_pid == pid) return st; } st = calloc(1, sizeof(th_stream_t)); - st->st_index = i; + sc = &st->st_sc; + sc->sc_index = i; + sc->sc_type = type; + LIST_INSERT_HEAD(&sp->sp_components, sc, sc_link); + st->st_pid = pid; - st->st_type = type; st->st_demuxer_fd = -1; - LIST_INSERT_HEAD(&t->tht_streams, st, st_link); TAILQ_INIT(&st->st_ptsq); TAILQ_INIT(&st->st_durationq); @@ -633,7 +653,8 @@ transport_is_tv(th_transport_t *t) int transport_is_available(th_transport_t *t) { - return transport_servicetype_txt(t) && LIST_FIRST(&t->tht_streams); + return transport_servicetype_txt(t) && + LIST_FIRST(&t->tht_streaming_pad.sp_components); } /** diff --git a/transports.h b/transports.h index 910aee2a..56f4ffbc 100644 --- a/transports.h +++ b/transports.h @@ -38,7 +38,7 @@ void transport_unmap_channel(th_transport_t *t); th_transport_t *transport_find(channel_t *ch, unsigned int weight); th_stream_t *transport_add_stream(th_transport_t *t, int pid, - tv_streamtype_t type); + streaming_component_type_t type); void transport_set_priority(th_transport_t *t, int prio); @@ -62,4 +62,21 @@ void transport_remove_subscriber(th_transport_t *t, th_subscription_t *s); //void transport_unlink_muxer(th_muxer_t *tm); +static inline th_stream_t * +transport_find_stream_by_pid(th_transport_t *t, int pid) +{ + streaming_pad_t *sp = &t->tht_streaming_pad; + th_stream_t *st; + streaming_component_t *sc; + + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; + if(st->st_pid == pid) + return st; + } + return NULL; +} + + + #endif /* TRANSPORTS_H */ diff --git a/tsdemux.c b/tsdemux.c index 5998038e..35334ec9 100644 --- a/tsdemux.c +++ b/tsdemux.c @@ -53,7 +53,7 @@ got_section(th_transport_t *t, th_stream_t *st) { th_descrambler_t *td; - if(st->st_type == HTSTV_CA) { + if(st->st_sc.sc_type == SCT_CA) { LIST_FOREACH(td, &t->tht_descramblers, td_transport_link) td->td_table(td, t, st, st->st_section->ps_data, st->st_section->ps_offset); @@ -95,11 +95,11 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, uint8_t *tsb) off = tsb[3] & 0x20 ? tsb[4] + 5 : 4; pusi = tsb[1] & 0x40; - switch(st->st_type) { + switch(st->st_sc.sc_type) { - case HTSTV_CA: - case HTSTV_PAT: - case HTSTV_PMT: + case SCT_CA: + case SCT_PAT: + case SCT_PMT: if(st->st_section == NULL) st->st_section = calloc(1, sizeof(struct psi_section)); @@ -125,7 +125,7 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, uint8_t *tsb) got_section(t, st); break; - case HTSTV_TELETEXT: + case SCT_TELETEXT: // teletext_input(t, tsb); break; @@ -195,12 +195,7 @@ ts_recv_packet1(th_transport_t *t, uint8_t *tsb) th_descrambler_t *td; pid = (tsb[1] & 0x1f) << 8 | tsb[2]; - - LIST_FOREACH(st, &t->tht_streams, st_link) - if(st->st_pid == pid) - break; - - if(st == NULL) + if((st = transport_find_stream_by_pid(t, pid)) == NULL) return; t->tht_packets = 1; @@ -250,15 +245,8 @@ void ts_recv_packet2(th_transport_t *t, uint8_t *tsb) { th_stream_t *st; - int pid; + int pid = (tsb[1] & 0x1f) << 8 | tsb[2]; - pid = (tsb[1] & 0x1f) << 8 | tsb[2]; - LIST_FOREACH(st, &t->tht_streams, st_link) - if(st->st_pid == pid) - break; - - if(st == NULL) - return; - - ts_recv_packet0(t, st, tsb); + if((st = transport_find_stream_by_pid(t, pid)) != NULL) + ts_recv_packet0(t, st, tsb); } diff --git a/tvhead.h b/tvhead.h index e378be74..cb865cd7 100644 --- a/tvhead.h +++ b/tvhead.h @@ -106,15 +106,70 @@ TAILQ_HEAD(th_refpkt_queue, th_refpkt); TAILQ_HEAD(th_muxpkt_queue, th_muxpkt); LIST_HEAD(autorec_list, autorec); TAILQ_HEAD(th_pktref_queue, th_pktref); +LIST_HEAD(streaming_target_list, streaming_target); +LIST_HEAD(streaming_component_list, streaming_component); -extern time_t dispatch_clock; -extern int startupcounter; -extern struct th_transport_list all_transports; -extern struct channel_tree channel_name_tree; -extern struct th_subscription_list subscriptions; -struct th_transport; -struct th_stream; + +typedef enum { + SCT_MPEG2VIDEO = 1, + SCT_MPEG2AUDIO, + SCT_H264, + SCT_AC3, + SCT_TELETEXT, + SCT_SUBTITLES, + SCT_CA, + SCT_PAT, + SCT_PMT, +} streaming_component_type_t; + +/** + * + */ +typedef struct streaming_component { + LIST_ENTRY(streaming_component) sc_link; + + streaming_component_type_t sc_type; + int sc_index; + + char sc_lang[4]; /* ISO 639 3-letter language code */ + +} streaming_component_t; + + + + + +/** + * A streaming pad generates data. + * + * It has one or more streaming_targets attached to it + */ +typedef struct streaming_pad { + struct streaming_target_list sp_targets; + struct streaming_component_list sp_components; + + pthread_mutex_t *sp_mutex; /* Mutex for protecting modification of + st_targets and delivery. + This needs to be created elsewhere */ +} streaming_pad_t; + + +/** + * A streaming target receives data + */ +typedef struct streaming_target { + LIST_ENTRY(streaming_target) st_link; + streaming_pad_t *st_pad; /* Source we are linked to */ + + pthread_mutex_t st_mutex; /* Protects sp_queue */ + pthread_cond_t st_cond; /* Condvar for signalling new + packets */ + + struct th_pktref_queue st_queue; + +} streaming_target_t; + /* * Video4linux adapter @@ -268,10 +323,14 @@ typedef void (pid_section_callback_t)(struct th_transport *t, uint8_t *section, int section_len); /* - * Stream, one media component for a transport + * Stream, one media component for a transport. + * + * XXX: This should be renamed to 'elementary_stream' or something */ typedef struct th_stream { - LIST_ENTRY(th_stream) st_link; + + streaming_component_t st_sc; + uint16_t st_pid; uint8_t st_cc; /* Last CC */ uint8_t st_cc_valid; /* Is CC valid at all? */ @@ -279,9 +338,7 @@ typedef struct th_stream { avgstat_t st_cc_errors; avgstat_t st_rate; - tv_streamtype_t st_type; int st_demuxer_fd; - int st_index; int st_peak_presentation_delay; /* Max seen diff. of DTS and PTS */ struct psi_section *st_section; @@ -338,8 +395,6 @@ typedef struct th_stream { uint16_t st_caid; - char st_lang[4]; /* ISO 639 3-letter language code */ - /* Remuxing information */ AVRational st_tb; @@ -589,19 +644,6 @@ typedef struct th_transport { pthread_mutex_t tht_stream_mutex; - /** - * Condition variable to wakeup transport streaming thread. - * - * Currently unused (All streaming is executed on the source - * thread) - */ - pthread_cond_t tht_stream_cond; - - /** - * List of all streams - */ - struct th_stream_list tht_streams; - /** * For simple streaming sources (such as video4linux) keeping * track of the video and audio stream is convenient. @@ -653,6 +695,14 @@ typedef struct th_transport { */ int tht_pmt_seen; + + /** + * Delivery pad, this is were we finally deliver all streaming output + */ + + streaming_pad_t tht_streaming_pad; + + } th_transport_t; @@ -839,7 +889,7 @@ typedef struct tt_decoder { char *utf8toprintable(const char *in); char *utf8tofilename(const char *in); -const char *htstvstreamtype2txt(tv_streamtype_t s); +const char *streaming_component_type2txt(streaming_component_type_t s); static inline unsigned int tvh_strhash(const char *s, unsigned int mod) { @@ -879,4 +929,15 @@ getclock_hires(void) } + + +extern time_t dispatch_clock; +extern int startupcounter; +extern struct th_transport_list all_transports; +extern struct channel_tree channel_name_tree; +extern struct th_subscription_list subscriptions; + +struct th_transport; +struct th_stream; + #endif /* TV_HEAD_H */ diff --git a/webui/extjs.c b/webui/extjs.c index 03d48cab..ee2664d0 100644 --- a/webui/extjs.c +++ b/webui/extjs.c @@ -500,6 +500,8 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) static htsmsg_t * build_transport_msg(th_transport_t *t) { + streaming_pad_t *sp = &t->tht_streaming_pad; + streaming_component_t *sc; htsmsg_t *r = htsmsg_create(); th_stream_t *st; @@ -522,15 +524,17 @@ build_transport_msg(th_transport_t *t) subtitles[0] = 0; scrambling[0] = 0; - LIST_FOREACH(st, &t->tht_streams, st_link) { - switch(st->st_type) { - case HTSTV_TELETEXT: - case HTSTV_SUBTITLES: - case HTSTV_PAT: - case HTSTV_PMT: + LIST_FOREACH(sc, &sp->sp_components, sc_link) { + st = (th_stream_t *)sc; + + switch(sc->sc_type) { + case SCT_TELETEXT: + case SCT_SUBTITLES: + case SCT_PAT: + case SCT_PMT: break; - case HTSTV_MPEG2VIDEO: + case SCT_MPEG2VIDEO: snprintf(video + strlen(video), sizeof(video) - strlen(video), "%sMPEG-2 (PID:%d", strlen(video) > 0 ? ", " : "", st->st_pid); @@ -546,33 +550,33 @@ build_transport_msg(th_transport_t *t) break; - case HTSTV_H264: + case SCT_H264: snprintf(video + strlen(video), sizeof(video) - strlen(video), "%sH.264 (PID:%d", strlen(video) > 0 ? ", " : "", st->st_pid); goto video; - case HTSTV_MPEG2AUDIO: + case SCT_MPEG2AUDIO: snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio), "%sMPEG-2 (PID:%d", strlen(audio) > 0 ? ", " : "", st->st_pid); audio: - if(st->st_lang[0]) { + if(sc->sc_lang[0]) { snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio), - ", languange: \"%s\")", st->st_lang); + ", languange: \"%s\")", sc->sc_lang); } else { snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio), ")"); } break; - case HTSTV_AC3: + case SCT_AC3: snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio), "%sAC3 (PID:%d", strlen(audio) > 0 ? ", " : "", st->st_pid); goto audio; - case HTSTV_CA: + case SCT_CA: snprintf(scrambling + strlen(scrambling), sizeof(scrambling) - strlen(scrambling), "%s%s", strlen(scrambling) > 0 ? ", " : "",