From 412cce5ea650a56fe6fcbbae6e8036157b80f5f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Fri, 14 Sep 2007 21:45:21 +0000 Subject: [PATCH] rework much of the internal transport stream handling --- Makefile | 4 +- channels.c | 1 - dispatch.c | 61 +++++++++++----------- dispatch.h | 14 +++++ dvb.c | 4 +- dvb_dvr.c | 2 +- htsclient.c | 5 +- iptv_input.c | 36 ++++++++++++- iptv_output.c | 3 +- dvb_pmt.c => psi.c | 124 +++++++++++++++++++++++++++++++++++---------- dvb_pmt.h => psi.h | 24 ++++++--- pvr.c | 5 +- transports.c | 99 ++++++++++++++++++++++++++---------- transports.h | 10 ++-- tvhead.h | 17 ++++--- v4l.c | 14 +++-- 16 files changed, 308 insertions(+), 115 deletions(-) rename dvb_pmt.c => psi.c (65%) rename dvb_pmt.h => psi.h (59%) diff --git a/Makefile b/Makefile index c5e2b37d..82c25811 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ include ../config.mak -SRCS = main.c dispatch.c channels.c transports.c teletext.c +SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c SRCS += pvr.c pvr_rec.c SRCS += epg.c epg_xmltv.c -SRCS += dvb.c dvb_support.c dvb_pmt.c dvb_dvr.c dvb_muxconfig.c +SRCS += dvb.c dvb_support.c dvb_dvr.c dvb_muxconfig.c SRCS += iptv_input.c iptv_output.c diff --git a/channels.c b/channels.c index a8e4db56..7a388aab 100644 --- a/channels.c +++ b/channels.c @@ -35,7 +35,6 @@ #include "v4l.h" #include "iptv_input.h" -#include "dvb_pmt.h" #include "channels.h" #include "transports.h" diff --git a/dispatch.c b/dispatch.c index 427dc1a4..3ac0b5a7 100644 --- a/dispatch.c +++ b/dispatch.c @@ -45,7 +45,7 @@ typedef struct stimer { LIST_ENTRY(stimer) link; void (*callback)(void *aux); void *aux; - time_t t; + int64_t t; } stimer_t; LIST_HEAD(, stimer) dispatch_timers; @@ -54,24 +54,33 @@ LIST_HEAD(, stimer) dispatch_timers; static int stimercmp(stimer_t *a, stimer_t *b) { - return a->t - b->t; + if(a->t < b->t) + return -1; + else if(a->t > b->t) + return 1; + return 0; } +void * +stimer_add_hires(void (*callback)(void *aux), void *aux, int64_t t) +{ + stimer_t *ti = malloc(sizeof(stimer_t)); + ti->t = t; + ti->aux = aux; + ti->callback = callback; + LIST_INSERT_SORTED(&dispatch_timers, ti, link, stimercmp); + return ti; +} + + + void * stimer_add(void (*callback)(void *aux), void *aux, int delta) { time_t now; - stimer_t *ti = malloc(sizeof(stimer_t)); - time(&now); - - ti->t = now + delta; - ti->aux = aux; - ti->callback = callback; - - LIST_INSERT_SORTED(&dispatch_timers, ti, link, stimercmp); - return ti; + return stimer_add_hires(callback, aux, (uint64_t)(now + delta) * 1000000ULL); } void @@ -87,37 +96,23 @@ static int stimer_next(void) { stimer_t *ti = LIST_FIRST(&dispatch_timers); - struct timeval tv; - int64_t next, now, delta; + int64_t delta; if(ti == NULL) return -1; - next = (uint64_t)ti->t * 1000000ULL; - - gettimeofday(&tv, NULL); - - now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec; - - delta = next - now; + delta = ti->t - getclock_hires(); return delta < 0 ? 0 : delta / 1000ULL; } - - - - - - static void -stimer_dispatch(time_t now) +stimer_dispatch(int64_t now) { stimer_t *ti; while((ti = LIST_FIRST(&dispatch_timers)) != NULL) { if(ti->t > now) break; - LIST_REMOVE(ti, link); ti->callback(ti->aux); free(ti); @@ -227,12 +222,18 @@ dispatcher(void) { struct epoll_entry *e; int i, n; + struct timeval tv; + int64_t now; static struct epoll_event events[EPOLL_FDS_PER_ROUND]; n = epoll_wait(epoll_fd, events, EPOLL_FDS_PER_ROUND, stimer_next()); - time(&dispatch_clock); + gettimeofday(&tv, NULL); + + dispatch_clock = tv.tv_sec; + now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec; + for(i = 0; i < n; i++) { e = events[i].data.ptr; @@ -257,5 +258,5 @@ dispatcher(void) dispatch_deref(e); } - stimer_dispatch(dispatch_clock); + stimer_dispatch(now); } diff --git a/dispatch.h b/dispatch.h index 7a50fbec..26fbd12f 100644 --- a/dispatch.h +++ b/dispatch.h @@ -19,6 +19,8 @@ #ifndef DISPATCH_H #define DISPATCH_H +#include + extern time_t dispatch_clock; #define DISPATCH_READ 0x1 @@ -26,6 +28,17 @@ extern time_t dispatch_clock; #define DISPATCH_ERR 0x4 #define DISPATCH_PRI 0x8 +extern inline int64_t +getclock_hires(void) +{ + int64_t now; + struct timeval tv; + + gettimeofday(&tv, NULL); + now = (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec; + return now; +} + int dispatch_init(void); void *dispatch_addfd(int fd, void (*callback)(int events, void *opaque, int fd), @@ -36,6 +49,7 @@ void dispatch_clr(void *handle, int flags); void dispatcher(void); void *stimer_add(void (*callback)(void *aux), void *aux, int delta); +void *stimer_add_hires(void (*callback)(void *aux), void *aux, int64_t t); void stimer_del(void *handle); #endif /* DISPATCH_H */ diff --git a/dvb.c b/dvb.c index 7297b4bc..6d9f9805 100644 --- a/dvb.c +++ b/dvb.c @@ -41,8 +41,8 @@ #include "transports.h" #include "teletext.h" #include "epg.h" +#include "psi.h" #include "dvb_support.h" -#include "dvb_pmt.h" #include "dvb_dvr.h" #include "dvb_muxconfig.h" @@ -327,7 +327,7 @@ dvb_service_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, { th_transport_t *t = opaque; - return dvb_parse_pmt(t, ptr, len); + return psi_parse_pmt(t, ptr, len, 1); } diff --git a/dvb_dvr.c b/dvb_dvr.c index 6a7e653c..a5547999 100644 --- a/dvb_dvr.c +++ b/dvb_dvr.c @@ -74,7 +74,7 @@ dvb_dvr_process_packets(th_dvb_adapter_t *tda, uint8_t *tsb, int r) while(r >= 188) { pid = (tsb[1] & 0x1f) << 8 | tsb[2]; LIST_FOREACH(t, &tda->tda_transports, tht_adapter_link) - transport_recv_tsb(t, pid, tsb); + transport_recv_tsb(t, pid, tsb, 1, AV_NOPTS_VALUE); r -= 188; tsb += 188; } diff --git a/htsclient.c b/htsclient.c index b52f02f7..621a231d 100644 --- a/htsclient.c +++ b/htsclient.c @@ -58,7 +58,8 @@ cprintf(client_t *c, const char *fmt, ...) static void -client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi) +client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi, + int64_t pcr) { client_t *c = s->ths_opaque; char stoppkt[4]; @@ -87,7 +88,7 @@ client_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi) } memcpy(s->ths_pkt + s->ths_pkt_ptr, pkt, 188); - + s->ths_pkt[s->ths_pkt_ptr] = pi->tp_type; s->ths_pkt_ptr += 188; if(s->ths_pkt_ptr == c->c_pkt_maxsiz + 2) { diff --git a/iptv_input.c b/iptv_input.c index b4123d8f..6e0814fe 100644 --- a/iptv_input.c +++ b/iptv_input.c @@ -39,6 +39,7 @@ #include "channels.h" #include "transports.h" #include "dispatch.h" +#include "psi.h" static void iptv_fd_callback(int events, void *opaque, int fd) @@ -52,7 +53,7 @@ iptv_fd_callback(int events, void *opaque, int fd) while(r >= 188) { pid = (tsb[1] & 0x1f) << 8 | tsb[2]; - transport_recv_tsb(t, pid, tsb); + transport_recv_tsb(t, pid, tsb, 1, AV_NOPTS_VALUE); r -= 188; tsb += 188; } @@ -121,6 +122,35 @@ iptv_stop_feed(th_transport_t *t) } +/* + * + */ + +static void +iptv_parse_pmt(struct th_transport *t, struct th_pid *pi, + uint8_t *table, int table_len) +{ + if(table[0] != 2) + return; + + psi_parse_pmt(t, table + 3, table_len - 3, 0); +} + + +/* + * + */ + +static void +iptv_parse_pat(struct th_transport *t, struct th_pid *pi, + uint8_t *table, int table_len) +{ + if(table[0] != 0) + return; + + psi_parse_pat(t, table + 3, table_len - 3, iptv_parse_pmt); +} + /* * */ @@ -134,6 +164,7 @@ iptv_configure_transport(th_transport_t *t, const char *muxname) char buf[100]; char ifname[100]; struct ifreq ifr; + th_pid_t *pi; if((ce = find_mux_config("iptvmux", muxname)) == NULL) return -1; @@ -178,5 +209,8 @@ iptv_configure_transport(th_transport_t *t, const char *muxname) ifname, inet_ntoa(t->tht_iptv_group_addr), t->tht_iptv_port); t->tht_name = strdup(buf); + pi = transport_add_pid(t, 0, HTSTV_TABLE); + pi->tp_got_section = iptv_parse_pat; + return 0; } diff --git a/iptv_output.c b/iptv_output.c index e6dc7580..30064df8 100644 --- a/iptv_output.c +++ b/iptv_output.c @@ -44,7 +44,8 @@ typedef struct output_multicast { static void -om_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi) +om_ip_streamer(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi, + int64_t pcr) { output_multicast_t *om = s->ths_opaque; struct sockaddr_in sin; diff --git a/dvb_pmt.c b/psi.c similarity index 65% rename from dvb_pmt.c rename to psi.c index 0783b767..d1e47bff 100644 --- a/dvb_pmt.c +++ b/psi.c @@ -1,5 +1,5 @@ /* - * TV Input - DVB - Program Map Table parser + * Multicasted IPTV Input * Copyright (C) 2007 Andreas Öman * * This program is free software: you can redistribute it and/or modify @@ -16,34 +16,45 @@ * along with this program. If not, see . */ -#include - -#include -#include -#include -#include - #include #include #include #include +#include + #include "tvhead.h" +#include "psi.h" #include "transports.h" #include "dvb_support.h" -const char * -htstvstreamtype2txt(tv_streamtype_t s) +int +psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len, + int start, int chkcrc) { - switch(s) { - case HTSTV_MPEG2VIDEO: return "mpeg2video"; - case HTSTV_MPEG2AUDIO: return "mpeg2audio"; - case HTSTV_H264: return "h264"; - case HTSTV_AC3: return "AC-3"; - case HTSTV_TELETEXT: return "teletext"; - case HTSTV_SUBTITLES: return "subtitles"; - default: return ""; + int remain, a, tsize; + + if(start) + ps->ps_offset = 0; + + if(ps->ps_offset < 0) + return -1; + + remain = PSI_SECTION_SIZE - ps->ps_offset; + + a = FFMAX(0, FFMIN(remain, len)); + + memcpy(ps->ps_data + ps->ps_offset, data, a); + ps->ps_offset += a; + tsize = 3 + (((ps->ps_data[1] & 0xf) << 8) | ps->ps_data[2]); + if(ps->ps_offset < tsize) + return -1; + + if(chkcrc) { + /* XXX: Add CRC check */ } + ps->ps_offset = tsize - (chkcrc ? 4 : 0); + return 0; } @@ -51,32 +62,73 @@ htstvstreamtype2txt(tv_streamtype_t s) +/** + * PAT parser, from ISO 13818-1 + */ + int -dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len) +psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len, + pid_section_callback_t *pmt_callback) +{ + uint16_t prognum; + uint16_t pid; + th_pid_t *pi; + + if(len < 5) + return -1; + + ptr += 5; + len -= 5; + + while(len >= 4) { + + prognum = ptr[0] << 8 | ptr[1]; + pid = (ptr[2] & 0x1f) << 8 | ptr[3]; + + if(prognum != 0) { + pi = transport_add_pid(t, pid, HTSTV_TABLE); + pi->tp_got_section = pmt_callback; + + } + ptr += 4; + len -= 4; + } + return 0; +} + + + + + +/** + * PMT parser, from ISO 13818-1 and ETSI EN 300 468 + */ + +int +psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid) { uint16_t pcr_pid, pid; uint8_t estype; int dllen; uint8_t dtag, dlen; uint16_t sid; - tv_streamtype_t hts_stream_type; if(len < 9) return -1; sid = ptr[0] << 8 | ptr[1]; - pcr_pid = (ptr[5] & 0x1f) << 8 | ptr[6]; dllen = (ptr[7] & 0xf) << 8 | ptr[8]; + + t->tht_pcr_pid = pcr_pid; ptr += 9; len -= 9; - if(sid != t->tht_dvb_service_id) + if(chksvcid && sid != t->tht_dvb_service_id) return -1; - - + while(dllen > 2) { dtag = ptr[0]; dlen = ptr[1]; @@ -92,7 +144,7 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len) estype = ptr[0]; pid = (ptr[1] & 0x1f) << 8 | ptr[2]; dllen = (ptr[3] & 0xf) << 8 | ptr[4]; - + ptr += 5; len -= 5; @@ -123,7 +175,6 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len) if(dlen > len) break; - switch(dtag) { case DVB_DESC_TELETEXT: if(estype == 0x06) @@ -134,7 +185,7 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len) break; case DVB_DESC_AC3: - if(estype == 0x06) + if(estype == 0x06 || estype == 0x81) hts_stream_type = HTSTV_AC3; break; } @@ -147,3 +198,22 @@ dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len) return 0; } + + + + + +const char * +htstvstreamtype2txt(tv_streamtype_t s) +{ + switch(s) { + case HTSTV_MPEG2VIDEO: return "mpeg2video"; + case HTSTV_MPEG2AUDIO: return "mpeg2audio"; + case HTSTV_H264: return "h264"; + case HTSTV_AC3: return "AC-3"; + case HTSTV_TELETEXT: return "teletext"; + case HTSTV_SUBTITLES: return "subtitles"; + default: return ""; + } +} + diff --git a/dvb_pmt.h b/psi.h similarity index 59% rename from dvb_pmt.h rename to psi.h index d168dda8..0fb7143d 100644 --- a/dvb_pmt.h +++ b/psi.h @@ -1,5 +1,5 @@ /* - * TV Input - Linux DVB interface + * Multicasted IPTV Input * Copyright (C) 2007 Andreas Öman * * This program is free software: you can redistribute it and/or modify @@ -16,11 +16,23 @@ * along with this program. If not, see . */ -#ifndef DVB_PMT_H -#define DVB_PMT_H +#ifndef PSI_H_ +#define PSI_H_ -int dvb_parse_pmt(th_transport_t *t, uint8_t *ptr, int len); +#define PSI_SECTION_SIZE 4096 -const char *htstvstreamtype2txt(tv_streamtype_t s); +typedef struct psi_section { + int ps_offset; + uint8_t ps_data[PSI_SECTION_SIZE]; +} psi_section_t; -#endif /* DVB_PMT_H */ + +int psi_section_reassemble(psi_section_t *ps, uint8_t *data, int len, + int pusi, int chkcrc); + +int psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len, + pid_section_callback_t *pmt_callback); + +int psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid); + +#endif /* PSI_H_ */ diff --git a/pvr.c b/pvr.c index eaea9f1e..5598e613 100644 --- a/pvr.c +++ b/pvr.c @@ -441,7 +441,7 @@ pvr_wait_thread(pvr_rec_t *pvrr) static void pvr_record_callback(struct th_subscription *s, uint8_t *pkt, - th_pid_t *pi); + th_pid_t *pi, int64_t pcr); static void @@ -528,7 +528,8 @@ pvrr_fsm(pvr_rec_t *pvrr) */ static void -pvr_record_callback(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi) +pvr_record_callback(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi, + int64_t pcr) { pvr_data_t *pd; pvr_rec_t *pvrr = s->ths_opaque; diff --git a/transports.c b/transports.c index f0fe3f0b..b6d232a5 100644 --- a/transports.c +++ b/transports.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,8 @@ #include +#include + #include "tvhead.h" #include "dispatch.h" #include "dvb_dvr.h" @@ -43,6 +46,7 @@ #include "v4l.h" #include "dvb_dvr.h" #include "iptv_input.h" +#include "psi.h" /* * transport_mutex protects all operations concerning subscription lists @@ -214,7 +218,7 @@ subscription_unsubscribe(th_subscription_t *s) { pthread_mutex_lock(&subscription_mutex); - s->ths_callback(s, NULL, NULL); + s->ths_callback(s, NULL, NULL, AV_NOPTS_VALUE); LIST_REMOVE(s, ths_global_link); LIST_REMOVE(s, ths_channel_link); @@ -249,7 +253,7 @@ subscription_sort(th_subscription_t *a, th_subscription_t *b) th_subscription_t * channel_subscribe(th_channel_t *ch, void *opaque, void (*callback)(struct th_subscription *s, - uint8_t *pkt, th_pid_t *pi), + uint8_t *pkt, th_pid_t *pi, int64_t pcr), unsigned int weight, const char *name) { @@ -316,7 +320,7 @@ transport_flush_subscribers(th_transport_t *t) while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) { LIST_REMOVE(s, ths_transport_link); s->ths_transport = NULL; - s->ths_callback(s, NULL, NULL); + s->ths_callback(s, NULL, NULL, AV_NOPTS_VALUE); } } @@ -345,13 +349,14 @@ transport_compute_weight(struct th_transport_list *head) */ void -transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb) +transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb, int scanpcr, + int64_t pcr) { th_pid_t *pi = NULL; th_subscription_t *s; - th_channel_t *ch; - int cc, err = 0; - + int cc, err = 0, afc, afl = 0; + int len, pusi; + LIST_FOREACH(pi, &t->tht_pids, tp_link) if(pi->tp_pid == pid) break; @@ -359,9 +364,12 @@ transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb) if(pi == NULL) return; - cc = tsb[3] & 0xf; + avgstat_add(&t->tht_rate, 188, dispatch_clock); - if(tsb[3] & 0x10) { + afc = (tsb[3] >> 4) & 3; + + if(afc & 1) { + cc = tsb[3] & 0xf; if(pi->tp_cc_valid && cc != pi->tp_cc) { /* Incorrect CC */ avgstat_add(&t->tht_cc_errors, 1, dispatch_clock); @@ -371,25 +379,63 @@ transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb) pi->tp_cc = (cc + 1) & 0xf; } - avgstat_add(&t->tht_rate, 188, dispatch_clock); + if(afc & 2) { + afl = tsb[4] + 1; - ch = t->tht_channel; + if(afl > 0 && scanpcr && tsb[5] & 0x10) { + pcr = (uint64_t)tsb[6] << 25; + pcr |= (uint64_t)tsb[7] << 17; + pcr |= (uint64_t)tsb[8] << 9; + pcr |= (uint64_t)tsb[9] << 1; + pcr |= (uint64_t)(tsb[10] >> 7) & 0x01; + } + } + + switch(pi->tp_type) { - if(pi->tp_type == HTSTV_TELETEXT) { - /* teletext */ + case HTSTV_TABLE: + if(pi->tp_section == NULL) + pi->tp_section = calloc(1, sizeof(struct psi_section)); + + afl += 4; + if(err || afl >= 188) { + pi->tp_section->ps_offset = -1; /* hold parser until next pusi */ + break; + } + + pusi = tsb[1] & 0x40; + + if(pusi) { + len = tsb[afl++]; + if(len > 0) { + if(len > 188 - afl) + break; + if(!psi_section_reassemble(pi->tp_section, tsb + afl, len, 0, 1)) + pi->tp_got_section(t, pi, pi->tp_section->ps_data, + pi->tp_section->ps_offset); + + afl += len; + } + } + + if(!psi_section_reassemble(pi->tp_section, tsb + afl, 188 - afl, pusi, 1)) + pi->tp_got_section(t, pi, pi->tp_section->ps_data, + pi->tp_section->ps_offset); + break; + + case HTSTV_TELETEXT: teletext_input(t, tsb); - return; + break; + + default: + pthread_mutex_lock(&subscription_mutex); + LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) { + s->ths_total_err += err; + s->ths_callback(s, tsb, pi, pcr); + } + pthread_mutex_unlock(&subscription_mutex); + break; } - - tsb[0] = pi->tp_type; - - pthread_mutex_lock(&subscription_mutex); - - LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) { - s->ths_total_err += err; - s->ths_callback(s, tsb, pi); - } - pthread_mutex_unlock(&subscription_mutex); } @@ -477,7 +523,7 @@ transport_scheduler_init(void) } -void +th_pid_t * transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type) { th_pid_t *pi; @@ -485,7 +531,7 @@ transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type) LIST_FOREACH(pi, &t->tht_pids, tp_link) { i++; if(pi->tp_pid == pid) - return; + return pi; } pi = calloc(1, sizeof(th_pid_t)); @@ -495,4 +541,5 @@ transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type) pi->tp_demuxer_fd = -1; LIST_INSERT_HEAD(&t->tht_pids, pi, tp_link); + return pi; } diff --git a/transports.h b/transports.h index b6d032b4..804aac59 100644 --- a/transports.h +++ b/transports.h @@ -19,6 +19,7 @@ #ifndef TRANSPORTS_H #define TRANSPORTS_H +#include void subscription_unsubscribe(th_subscription_t *s); void subscription_set_weight(th_subscription_t *s, unsigned int weight); @@ -30,11 +31,13 @@ unsigned int transport_compute_weight(struct th_transport_list *head); void transport_flush_subscribers(th_transport_t *t); -void transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb); +void transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb, + int scanpcr, int64_t pcr); void transport_monitor_init(th_transport_t *t); -void transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type); +th_pid_t *transport_add_pid(th_transport_t *t, uint16_t pid, + tv_streamtype_t type); int transport_set_channel(th_transport_t *th, const char *name); @@ -43,7 +46,8 @@ void transport_scheduler_init(void); th_subscription_t *channel_subscribe(th_channel_t *ch, void *opaque, void (*ths_callback) (struct th_subscription *s, - uint8_t *pkt, th_pid_t *pi), + uint8_t *pkt, th_pid_t *pi, + int64_t pcr), unsigned int weight, const char *name); diff --git a/tvhead.h b/tvhead.h index 1472834e..5f7efb5e 100644 --- a/tvhead.h +++ b/tvhead.h @@ -209,7 +209,12 @@ typedef struct th_iptv_adapter { * */ +struct th_transport; +struct th_pid; +typedef void (pid_section_callback_t)(struct th_transport *t, + struct th_pid *pi, + uint8_t *section, int section_len); typedef struct th_pid { LIST_ENTRY(th_pid) tp_link; @@ -221,6 +226,8 @@ typedef struct th_pid { int tp_demuxer_fd; int tp_index; + struct psi_section *tp_section; + pid_section_callback_t *tp_got_section; } th_pid_t; typedef enum { @@ -257,6 +264,7 @@ typedef struct th_transport { struct th_pid_list tht_pids; + uint16_t tht_pcr_pid; uint16_t tht_dvb_network_id; uint16_t tht_dvb_transport_id; uint16_t tht_dvb_service_id; @@ -288,10 +296,7 @@ typedef struct th_transport { struct th_v4l_adapter *adapter; } v4l; - - struct { - struct in_addr group_addr; struct in_addr interface_addr; int ifindex; @@ -299,9 +304,7 @@ typedef struct th_transport { int port; int fd; void *dispatch_handle; - } iptv; - } u; @@ -398,7 +401,8 @@ typedef struct th_subscription { LIST_ENTRY(th_subscription) ths_subscriber_link; /* Caller is responsible for this link */ - void (*ths_callback)(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi); + void (*ths_callback)(struct th_subscription *s, uint8_t *pkt, th_pid_t *pi, + int64_t pcr); void *ths_opaque; @@ -547,5 +551,6 @@ config_entry_t *find_mux_config(const char *muxtype, const char *muxname); char *utf8toprintable(const char *in); char *utf8tofilename(const char *in); +const char *htstvstreamtype2txt(tv_streamtype_t s); #endif /* TV_HEAD_H */ diff --git a/v4l.c b/v4l.c index f71e7d9d..7cb8a8b0 100644 --- a/v4l.c +++ b/v4l.c @@ -464,7 +464,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type, uint32_t sc; uint8_t tsb0[188]; uint8_t *tsb, *src; - int64_t ts; + int64_t ts, pcr = AV_NOPTS_VALUE; int hlen, tlen, slen, plen, cc, pad; uint16_t u16; th_transport_t *t; @@ -482,6 +482,8 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type, sc = 0x1e0; p.tp_type = HTSTV_MPEG2VIDEO; p.tp_pid = 100; + if(pts != AV_NOPTS_VALUE) + pcr = dts; } tsb = tsb0; @@ -489,7 +491,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type, slen = len; len += 13; - *tsb++ = type; + *tsb++ = 0x47; *tsb++ = p.tp_pid >> 8 | 0x40; /* payload unit start indicator */ *tsb++ = p.tp_pid; @@ -549,8 +551,10 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type, memcpy(tsb, src, plen); - LIST_FOREACH(t, &tva->tva_transports, tht_adapter_link) - transport_recv_tsb(t, p.tp_pid, tsb0); + LIST_FOREACH(t, &tva->tva_transports, tht_adapter_link) { + transport_recv_tsb(t, p.tp_pid, tsb0, 0, pcr); + pcr = AV_NOPTS_VALUE; + } slen -= plen; if(slen == 0) @@ -560,7 +564,7 @@ v4l_ts_generate(th_v4l_adapter_t *tva, uint8_t *ptr, int len, int type, tsb = tsb0; - *tsb++ = type; + *tsb++ = 0x47; *tsb++ = p.tp_pid >> 8; *tsb++ = p.tp_pid;