From 14ff47028b18c0ba60fad07c772a43b6cb2098cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Fri, 4 Jun 2010 20:33:16 +0000 Subject: [PATCH] Maintain the order of PIDs as they appear in the PMT. Fixes bug #218 --- src/capmt.c | 2 +- src/cwc.c | 2 +- src/dvb/dvb_multiplex.c | 2 +- src/dvb/dvb_transport.c | 4 +- src/psi.c | 94 ++++++++++++++++++++++++++++++++++------- src/subscriptions.c | 4 +- src/transports.c | 25 +++++------ src/transports.h | 12 ------ src/tsdemux.c | 4 +- src/tvhead.h | 6 ++- src/webui/extjs.c | 2 +- src/webui/statedump.c | 2 +- 12 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/capmt.c b/src/capmt.c index b98f5a4e..dd72e69e 100644 --- a/src/capmt.c +++ b/src/capmt.c @@ -624,7 +624,7 @@ capmt_transport_start(th_transport_t *t) ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188); ct->ct_seq = capmt->capmt_seq++; - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { caid_t *c = LIST_FIRST(&st->st_caids); if(c == NULL) continue; diff --git a/src/cwc.c b/src/cwc.c index 1a5b3d78..fc29c096 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -1367,7 +1367,7 @@ cwc_find_stream_by_caid(th_transport_t *t, int caid) th_stream_t *st; caid_t *c; - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { LIST_FOREACH(c, &st->st_caids, link) { if(c->caid == caid) return st; diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index 2d2b379e..6edd46b1 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -1110,7 +1110,7 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src) pthread_mutex_lock(&t_src->tht_stream_mutex); pthread_mutex_lock(&t_dst->tht_stream_mutex); - LIST_FOREACH(st_src, &t_src->tht_components, st_link) { + TAILQ_FOREACH(st_src, &t_src->tht_components, st_link) { st_dst = transport_stream_create(t_dst, diff --git a/src/dvb/dvb_transport.c b/src/dvb/dvb_transport.c index b4867c78..e4dbff97 100644 --- a/src/dvb/dvb_transport.c +++ b/src/dvb/dvb_transport.c @@ -55,7 +55,7 @@ dvb_transport_open_demuxers(th_dvb_adapter_t *tda, th_transport_t *t) int fd; th_stream_t *st; - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { if(st->st_pid >= 0x2000) continue; @@ -162,7 +162,7 @@ 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_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { if(st->st_demuxer_fd != -1) { close(st->st_demuxer_fd); st->st_demuxer_fd = -1; diff --git a/src/psi.c b/src/psi.c index 112c0c7d..3055194a 100644 --- a/src/psi.c +++ b/src/psi.c @@ -222,6 +222,7 @@ psi_build_pat(th_transport_t *t, uint8_t *buf, int maxlen, int pmtpid) #define PMT_UPDATE_CA_PROVIDER_CHANGE 0x200 #define PMT_UPDATE_PARENT_PID 0x400 #define PMT_UPDATE_CAID_DELETED 0x800 +#define PMT_REORDERED 0x1000 /** * Add a CA descriptor @@ -240,6 +241,8 @@ psi_desc_add_ca(th_transport_t *t, uint16_t caid, uint32_t provid, uint16_t pid) st->st_delete_me = 0; + st->st_position = 0x40000; + LIST_FOREACH(c, &st->st_caids, link) { if(c->caid == caid) { c->delete_me = 0; @@ -288,10 +291,10 @@ psi_desc_ca(th_transport_t *t, const uint8_t *buffer, int size) //Add extra providers, if any for (i = 17; i < size; i += 15){ - uint16_t _pid = ((buffer[i]&0x1F) << 8) | buffer[i + 1]; - uint16_t _provid = (buffer[i + 2] << 8) | buffer[i + 3]; + uint16_t xpid = ((buffer[i]&0x1F) << 8) | buffer[i + 1]; + uint16_t xprovid = (buffer[i + 2] << 8) | buffer[i + 3]; - r |= psi_desc_add_ca(t, caid, _provid, _pid); + r |= psi_desc_add_ca(t, caid, xprovid, xpid); } break; case 0x0500:// Viaccess @@ -322,7 +325,7 @@ psi_desc_ca(th_transport_t *t, const uint8_t *buffer, int size) */ static int psi_desc_teletext(th_transport_t *t, const uint8_t *ptr, int size, - int parent_pid) + int parent_pid, int *position) { int r = 0; th_stream_t *st; @@ -354,6 +357,12 @@ psi_desc_teletext(th_transport_t *t, const uint8_t *ptr, int size, r |= PMT_UPDATE_PARENT_PID; st->st_parent_pid = parent_pid; } + + if(st->st_position != *position) { + st->st_position = *position; + r |= PMT_REORDERED; + } + (*position)++; } ptr += 5; size -= 5; @@ -361,6 +370,42 @@ psi_desc_teletext(th_transport_t *t, const uint8_t *ptr, int size, return r; } +/** + * + */ +static int +pidcmp(const void *A, const void *B) +{ + th_stream_t *a = *(th_stream_t **)A; + th_stream_t *b = *(th_stream_t **)B; + return a->st_position - b->st_position; +} + + + +/** + * + */ +static void +sort_pids(th_transport_t *t) +{ + th_stream_t *st, **v; + int num = 0, i = 0; + + TAILQ_FOREACH(st, &t->tht_components, st_link) + num++; + + v = alloca(num * sizeof(th_stream_t *)); + TAILQ_FOREACH(st, &t->tht_components, st_link) + v[i++] = st; + + qsort(v, num, sizeof(th_stream_t *), pidcmp); + + TAILQ_INIT(&t->tht_components); + for(i = 0; i < num; i++) + TAILQ_INSERT_TAIL(&t->tht_components, v[i], st_link); +} + /** * PMT parser, from ISO 13818-1 and ETSI EN 300 468 @@ -383,6 +428,9 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, int composition_id; int ancillary_id; int version; + int position = 0; + int tt_position = 1000; + caid_t *c, *cn; if(len < 9) @@ -390,7 +438,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, lock_assert(&t->tht_stream_mutex); - had_components = !!LIST_FIRST(&t->tht_components); + had_components = !!TAILQ_FIRST(&t->tht_components); sid = ptr[0] << 8 | ptr[1]; version = ptr[2] >> 1 & 0x1f; @@ -416,15 +464,15 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, /* Mark all streams for deletion */ if(delete) { - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { st->st_delete_me = 1; LIST_FOREACH(c, &st->st_caids, link) c->delete_me = 1; - } } + // Common descriptors while(dllen > 1) { dtag = ptr[0]; dlen = ptr[1]; @@ -441,11 +489,11 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, default: break; } - - len -= dlen; ptr += dlen; dllen -= dlen; } + + while(len >= 5) { estype = ptr[0]; pid = (ptr[1] & 0x1f) << 8 | ptr[2]; @@ -515,7 +563,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, if(estype == 0x06) hts_stream_type = SCT_TELETEXT; - update |= psi_desc_teletext(t, ptr, dlen, pid); + update |= psi_desc_teletext(t, ptr, dlen, pid, &tt_position); break; case DVB_DESC_AC3: @@ -553,6 +601,11 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, st->st_delete_me = 0; + if(st->st_position != position) { + update |= PMT_REORDERED; + st->st_position = position; + } + st->st_tb = (AVRational){1, 90000}; if(memcmp(st->st_lang, lang, 4)) { @@ -575,11 +628,12 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, update |= PMT_UPDATE_ANCILLARY_ID; } } + position++; } /* Scan again to see if any streams should be deleted */ - for(st = LIST_FIRST(&t->tht_components); st != NULL; st = next) { - next = LIST_NEXT(st, st_link); + for(st = TAILQ_FIRST(&t->tht_components); st != NULL; st = next) { + next = TAILQ_NEXT(st, st_link); for(c = LIST_FIRST(&st->st_caids); c != NULL; c = cn) { cn = LIST_NEXT(c, link); @@ -597,9 +651,12 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, } } + if(update & PMT_REORDERED) + sort_pids(t); + if(update) { tvhlog(LOG_DEBUG, "PSI", "Transport \"%s\" PMT (version %d) updated" - "%s%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s%s", transport_nicename(t), version, update&PMT_UPDATE_PCR ? ", PCR PID changed":"", update&PMT_UPDATE_NEW_STREAM ? ", New elementary stream":"", @@ -612,7 +669,8 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, update&PMT_UPDATE_NEW_CAID ? ", New CAID":"", update&PMT_UPDATE_CA_PROVIDER_CHANGE? ", CA provider changed":"", update&PMT_UPDATE_PARENT_PID ? ", Parent PID changed":"", - update&PMT_UPDATE_CAID_DELETED ? ", CAID deleted":""); + update&PMT_UPDATE_CAID_DELETED ? ", CAID deleted":"", + update&PMT_REORDERED ? ", PIDs reordered":""); transport_request_save(t); @@ -882,12 +940,13 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t) lock_assert(&t->tht_stream_mutex); - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { sub = htsmsg_create_map(); htsmsg_add_u32(sub, "pid", st->st_pid); htsmsg_add_str(sub, "type", val2str(st->st_type, streamtypetab) ?: "?"); - + htsmsg_add_u32(sub, "position", st->st_position); + if(st->st_lang[0]) htsmsg_add_str(sub, "language", st->st_lang); @@ -1039,6 +1098,8 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t) if(!htsmsg_get_u32(c, "frameduration", &u32)) st->st_frame_duration = u32; + if(!htsmsg_get_u32(c, "position", &u32)) + st->st_position = u32; load_legacy_caid(c, st); load_caid(c, st); @@ -1056,4 +1117,5 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t) st->st_parent_pid = u32; } } + sort_pids(t); } diff --git a/src/subscriptions.c b/src/subscriptions.c index 7dabc537..72ab8824 100644 --- a/src/subscriptions.c +++ b/src/subscriptions.c @@ -74,7 +74,7 @@ subscription_link_transport(th_subscription_t *s, th_transport_t *t) pthread_mutex_lock(&t->tht_stream_mutex); - if(LIST_FIRST(&t->tht_components) != NULL) + if(TAILQ_FIRST(&t->tht_components) != NULL) s->ths_start_message = streaming_msg_create_data(SMT_START, transport_build_stream_start(t)); @@ -114,7 +114,7 @@ subscription_unlink_transport(th_subscription_t *s, int reason) // Unlink from transport output streaming_target_disconnect(&t->tht_streaming_pad, &s->ths_input); - if(LIST_FIRST(&t->tht_components) != NULL && + if(TAILQ_FIRST(&t->tht_components) != NULL && s->ths_state == SUBSCRIPTION_GOT_TRANSPORT) { // Send a STOP message to the subscription client sm = streaming_msg_create_code(SMT_STOP, reason); diff --git a/src/transports.c b/src/transports.c index a27bfc94..057bdf9b 100644 --- a/src/transports.c +++ b/src/transports.c @@ -173,7 +173,7 @@ transport_stream_destroy(th_transport_t *t, th_stream_t *st) { if(t->tht_status == TRANSPORT_RUNNING) stream_clean(st); - LIST_REMOVE(st, st_link); + TAILQ_REMOVE(&t->tht_components, st, st_link); free(st->st_nicename); free(st); } @@ -204,7 +204,7 @@ transport_stop(th_transport_t *t) /** * Clean up each stream */ - LIST_FOREACH(st, &t->tht_components, st_link) + TAILQ_FOREACH(st, &t->tht_components, st_link) stream_clean(st); t->tht_status = TRANSPORT_IDLE; @@ -268,7 +268,7 @@ transport_start(th_transport_t *t, unsigned int weight, int force_start) /** * Initialize stream */ - LIST_FOREACH(st, &t->tht_components, st_link) + TAILQ_FOREACH(st, &t->tht_components, st_link) stream_init(st); pthread_mutex_unlock(&t->tht_stream_mutex); @@ -514,8 +514,8 @@ transport_destroy(th_transport_t *t) free(t->tht_svcname); free(t->tht_provider); - while((st = LIST_FIRST(&t->tht_components)) != NULL) { - LIST_REMOVE(st, st_link); + while((st = TAILQ_FIRST(&t->tht_components)) != NULL) { + TAILQ_REMOVE(&t->tht_components, st, st_link); free(st->st_nicename); free(st); } @@ -546,6 +546,7 @@ transport_create(const char *identifier, int type, int source_type) t->tht_refcount = 1; t->tht_enabled = 1; t->tht_pcr_last = AV_NOPTS_VALUE; + TAILQ_INIT(&t->tht_components); streaming_pad_init(&t->tht_streaming_pad); @@ -617,7 +618,7 @@ transport_make_nicename(th_transport_t *t) free(t->tht_nicename); t->tht_nicename = strdup(buf); - LIST_FOREACH(st, &t->tht_components, st_link) + TAILQ_FOREACH(st, &t->tht_components, st_link) transport_stream_make_nicename(t, st); } @@ -634,7 +635,7 @@ transport_stream_create(th_transport_t *t, int pid, int idx = 0; lock_assert(&t->tht_stream_mutex); - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { if(st->st_index > idx) idx = st->st_index; i++; @@ -646,7 +647,7 @@ transport_stream_create(th_transport_t *t, int pid, st->st_index = idx + 1; st->st_type = type; - LIST_INSERT_HEAD(&t->tht_components, st, st_link); + TAILQ_INSERT_TAIL(&t->tht_components, st, st_link); st->st_transport = t; st->st_pid = pid; @@ -682,7 +683,7 @@ transport_stream_find(th_transport_t *t, int pid) lock_assert(&t->tht_stream_mutex); - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { if(st->st_pid == pid) return st; } @@ -825,7 +826,7 @@ transport_restart(th_transport_t *t, int had_components) if(t->tht_refresh_feed != NULL) t->tht_refresh_feed(t); - if(LIST_FIRST(&t->tht_components) != NULL) { + if(TAILQ_FIRST(&t->tht_components) != NULL) { sm = streaming_msg_create_data(SMT_START, transport_build_stream_start(t)); @@ -847,7 +848,7 @@ transport_build_stream_start(th_transport_t *t) lock_assert(&t->tht_stream_mutex); - LIST_FOREACH(st, &t->tht_components, st_link) + TAILQ_FOREACH(st, &t->tht_components, st_link) n++; ss = calloc(1, sizeof(streaming_start_t) + @@ -856,7 +857,7 @@ transport_build_stream_start(th_transport_t *t) ss->ss_num_components = n; n = 0; - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { streaming_start_component_t *ssc = &ss->ss_components[n++]; ssc->ssc_index = st->st_index; ssc->ssc_type = st->st_type; diff --git a/src/transports.h b/src/transports.h index 975e1221..49db5a0e 100644 --- a/src/transports.h +++ b/src/transports.h @@ -66,18 +66,6 @@ void transport_remove_subscriber(th_transport_t *t, th_subscription_t *s, void transport_set_streaming_status_flags(th_transport_t *t, int flag); -static inline th_stream_t * -transport_find_stream_by_pid(th_transport_t *t, int pid) -{ - th_stream_t *st; - - LIST_FOREACH(st, &t->tht_components, st_link) { - if(st->st_pid == pid) - return st; - } - return NULL; -} - struct streaming_start; struct streaming_start *transport_build_stream_start(th_transport_t *t); diff --git a/src/tsdemux.c b/src/tsdemux.c index 1073413c..664e0a25 100644 --- a/src/tsdemux.c +++ b/src/tsdemux.c @@ -202,7 +202,7 @@ ts_recv_packet1(th_transport_t *t, const uint8_t *tsb, int64_t *pcrp) pid = (tsb[1] & 0x1f) << 8 | tsb[2]; - st = transport_find_stream_by_pid(t, pid); + st = transport_stream_find(t, pid); /* Extract PCR */ if(tsb[3] & 0x20 && tsb[4] > 0 && tsb[5] & 0x10) @@ -260,7 +260,7 @@ ts_recv_packet2(th_transport_t *t, const uint8_t *tsb) th_stream_t *st; int pid = (tsb[1] & 0x1f) << 8 | tsb[2]; - if((st = transport_find_stream_by_pid(t, pid)) != NULL) + if((st = transport_stream_find(t, pid)) != NULL) ts_recv_packet0(t, st, tsb); } diff --git a/src/tvhead.h b/src/tvhead.h index 0561bed4..fb4b25a4 100644 --- a/src/tvhead.h +++ b/src/tvhead.h @@ -110,6 +110,7 @@ LIST_HEAD(th_transport_list, th_transport); RB_HEAD(th_transport_tree, th_transport); TAILQ_HEAD(th_transport_queue, th_transport); LIST_HEAD(th_stream_list, th_stream); +TAILQ_HEAD(th_stream_queue, th_stream); LIST_HEAD(th_muxer_list, th_muxer); LIST_HEAD(th_muxstream_list, th_muxstream); LIST_HEAD(th_descrambler_list, th_descrambler); @@ -359,7 +360,8 @@ typedef struct caid { */ typedef struct th_stream { - LIST_ENTRY(th_stream) st_link; + TAILQ_ENTRY(th_stream) st_link; + int st_position; struct th_transport *st_transport; streaming_component_type_t st_type; @@ -759,7 +761,7 @@ typedef struct th_transport { /** * List of all components. */ - struct th_stream_list tht_components; + struct th_stream_queue tht_components; /** diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 07a1c351..1ed48ca7 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -1054,7 +1054,7 @@ extjs_servicedetails(http_connection_t *hc, streams = htsmsg_create_list(); - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { c = htsmsg_create_map(); htsmsg_add_u32(c, "pid", st->st_pid); diff --git a/src/webui/statedump.c b/src/webui/statedump.c index 2e819309..e28cb5b1 100644 --- a/src/webui/statedump.c +++ b/src/webui/statedump.c @@ -106,7 +106,7 @@ dumptransports(htsbuf_queue_t *hq, struct th_transport_list *l, int indent) htsbuf_qprintf(hq, "%*.s-------------------------------------------\n", indent + 4, ""); - LIST_FOREACH(st, &t->tht_components, st_link) { + TAILQ_FOREACH(st, &t->tht_components, st_link) { caid_t *caid; htsbuf_qprintf(hq, "%*.s%-16s %-5d %-5d %-5s\n", indent + 4, "", streaming_component_type2txt(st->st_type),