From be1a42d9092550ffa892e39ef91026e1405192d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Sat, 18 Jul 2009 20:07:47 +0000 Subject: [PATCH] * Try to detect duplicate EPG entries from the DVB feed and adjust EPG accordingly. The EPG code will search for events with the same DVB event ID +- 2 events from the current one. If the event id is equal, the prvious (old) entry will be removed in favor of the new one. Reason for not blindingly trusting the event id is that some networks seem to (incorrectly) reuse IDs. Ticket #65 --- debian/changelog | 7 ++ src/dvb/dvb_tables.c | 3 +- src/epg.c | 242 ++++++++++++++++++++++++------------------- src/epg.h | 8 +- src/xmltv.c | 2 +- 5 files changed, 147 insertions(+), 115 deletions(-) diff --git a/debian/changelog b/debian/changelog index c801cb35..616931db 100644 --- a/debian/changelog +++ b/debian/changelog @@ -69,6 +69,13 @@ hts-tvheadend (2.3) hts; urgency=low * Add exponential backoff for reconnect attempt in code word client. Ticket #80 + * Try to detect duplicate EPG entries from the DVB feed and adjust + EPG accordingly. The EPG code will search for events with the same + DVB event ID +- 2 events from the current one. If the event id is + equal, the prvious (old) entry will be removed in favor of the new one. + Reason for not blindingly trusting the event id is that some networks + seem to (incorrectly) reuse IDs. + hts-tvheadend (2.2) hts; urgency=low * Set $HOME so forked processes (XMLTV) will have correct environment diff --git a/src/dvb/dvb_tables.c b/src/dvb/dvb_tables.c index 34addda2..2364b7c6 100644 --- a/src/dvb/dvb_tables.c +++ b/src/dvb/dvb_tables.c @@ -522,7 +522,8 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, continue; } - if((e = epg_event_create(ch, start_time, start_time + duration)) == NULL) { + if((e = epg_event_create(ch, start_time, start_time + duration, + event_id)) == NULL) { len -= dllen; ptr += dllen; continue; diff --git a/src/epg.c b/src/epg.c index 938a1c3c..ce2a5630 100644 --- a/src/epg.c +++ b/src/epg.c @@ -165,114 +165,6 @@ epg_event_set_content_type(event_t *e, epg_content_type_t *ect) } -/** - * - */ -event_t * -epg_event_create(channel_t *ch, time_t start, time_t stop) -{ - static event_t *skel; - event_t *e; - static int tally; - - if((stop - start) > 11 * 3600) - return NULL; - - if(stop <= start) - return NULL; - - lock_assert(&global_lock); - - if(skel == NULL) - skel = calloc(1, sizeof(event_t)); - - skel->e_start = start; - - e = RB_INSERT_SORTED(&ch->ch_epg_events, skel, e_channel_link, e_ch_cmp); - if(e == NULL) { - /* New entry was inserted */ - e = skel; - skel = NULL; - - e->e_id = ++tally; - e->e_stop = stop; - - LIST_INSERT_HEAD(&epg_hash[e->e_id & EPG_GLOBAL_HASH_MASK], e, - e_global_link); - - e->e_refcount = 1; - e->e_channel = ch; - epg_event_changed(e); - - if(e == RB_FIRST(&ch->ch_epg_events)) { - /* First in temporal order, arm expiration timer */ - - gtimer_arm_abs(&ch->ch_epg_timer_head, epg_expire_event_from_channel, - ch, e->e_stop); - } - - - - if(ch->ch_epg_timer_current.gti_callback == NULL || - start < ch->ch_epg_timer_current.gti_expire) { - - gtimer_arm_abs(&ch->ch_epg_timer_current, epg_ch_check_current_event, - ch, e->e_start); - } - } else { - /* Already exist */ - - if(stop > e->e_stop) { - /* We allow the event to extend in time */ -#if 0 - printf("Event %s on %s extended stop time\n", e->e_title, - e->e_channel->ch_name); - printf("Previous %s", ctime(&e->e_stop)); - printf(" New %s", ctime(&stop)); -#endif - e->e_stop = stop; - epg_event_changed(e); - - if(e == ch->ch_epg_current) { - gtimer_arm_abs(&ch->ch_epg_timer_current, epg_ch_check_current_event, - ch, e->e_start); - } - } - } - return e; -} - - -/** - * - */ -event_t * -epg_event_find_by_time(channel_t *ch, time_t t) -{ - event_t skel, *e; - - skel.e_start = t; - e = RB_FIND_LE(&ch->ch_epg_events, &skel, e_channel_link, e_ch_cmp); - if(e == NULL || e->e_stop < t) - return NULL; - return e; -} - - -/** - * - */ -event_t * -epg_event_find_by_id(int eventid) -{ - event_t *e; - - LIST_FOREACH(e, &epg_hash[eventid & EPG_GLOBAL_HASH_MASK], e_global_link) - if(e->e_id == eventid) - break; - return e; -} - /** * @@ -333,6 +225,140 @@ epg_remove_event_from_channel(channel_t *ch, event_t *e) } +/** + * + */ +event_t * +epg_event_create(channel_t *ch, time_t start, time_t stop, int dvb_id) +{ + static event_t *skel; + event_t *e, *p, *n; + static int tally; + + if((stop - start) > 11 * 3600) + return NULL; + + if(stop <= start) + return NULL; + + lock_assert(&global_lock); + + if(skel == NULL) + skel = calloc(1, sizeof(event_t)); + + skel->e_start = start; + + e = RB_INSERT_SORTED(&ch->ch_epg_events, skel, e_channel_link, e_ch_cmp); + if(e == NULL) { + /* New entry was inserted */ + e = skel; + skel = NULL; + + e->e_id = ++tally; + e->e_stop = stop; + e->e_dvb_id = dvb_id; + + LIST_INSERT_HEAD(&epg_hash[e->e_id & EPG_GLOBAL_HASH_MASK], e, + e_global_link); + + e->e_refcount = 1; + e->e_channel = ch; + epg_event_changed(e); + + if(e == RB_FIRST(&ch->ch_epg_events)) { + /* First in temporal order, arm expiration timer */ + + gtimer_arm_abs(&ch->ch_epg_timer_head, epg_expire_event_from_channel, + ch, e->e_stop); + } + + + + if(ch->ch_epg_timer_current.gti_callback == NULL || + start < ch->ch_epg_timer_current.gti_expire) { + + gtimer_arm_abs(&ch->ch_epg_timer_current, epg_ch_check_current_event, + ch, e->e_start); + } + } else { + /* Already exist */ + + if(stop > e->e_stop) { + /* We allow the event to extend in time */ +#if 0 + printf("Event %s on %s extended stop time\n", e->e_title, + e->e_channel->ch_name); + printf("Previous %s", ctime(&e->e_stop)); + printf(" New %s", ctime(&stop)); +#endif + e->e_stop = stop; + epg_event_changed(e); + + if(e == ch->ch_epg_current) { + gtimer_arm_abs(&ch->ch_epg_timer_current, epg_ch_check_current_event, + ch, e->e_start); + } + } + } + + + if(dvb_id != -1) { + /* Erase any close events with the same DVB event id */ + + if((p = RB_PREV(e, e_channel_link)) != NULL) { + if(p->e_dvb_id == dvb_id) { + epg_remove_event_from_channel(ch, p); + } else if((p = RB_PREV(p, e_channel_link)) != NULL) { + if(p->e_dvb_id == dvb_id) + epg_remove_event_from_channel(ch, p); + } + } + + if((n = RB_NEXT(e, e_channel_link)) != NULL) { + if(n->e_dvb_id == dvb_id) { + epg_remove_event_from_channel(ch, n); + } else if((n = RB_NEXT(n, e_channel_link)) != NULL) { + if(n->e_dvb_id == dvb_id) + epg_remove_event_from_channel(ch, n); + } + } + } + return e; +} + + +/** + * + */ +event_t * +epg_event_find_by_time(channel_t *ch, time_t t) +{ + event_t skel, *e; + + skel.e_start = t; + e = RB_FIND_LE(&ch->ch_epg_events, &skel, e_channel_link, e_ch_cmp); + if(e == NULL || e->e_stop < t) + return NULL; + return e; +} + + +/** + * + */ +event_t * +epg_event_find_by_id(int eventid) +{ + event_t *e; + + LIST_FOREACH(e, &epg_hash[eventid & EPG_GLOBAL_HASH_MASK], e_global_link) + if(e->e_id == eventid) + break; + return e; +} + + + /** * */ diff --git a/src/epg.h b/src/epg.h index 3a3952b1..9c922e2d 100644 --- a/src/epg.h +++ b/src/epg.h @@ -61,10 +61,7 @@ typedef struct event { const char *e_title; /* UTF-8 encoded */ const char *e_desc; /* UTF-8 encoded */ - int e_source; /* higer is better, and we never downgrade */ - -#define EVENT_SRC_XMLTV 1 -#define EVENT_SRC_DVB 2 + int e_dvb_id; } event_t; @@ -80,7 +77,8 @@ void epg_event_set_desc(event_t *e, const char *desc); void epg_event_set_content_type(event_t *e, epg_content_type_t *ect); -event_t *epg_event_create(channel_t *ch, time_t start, time_t stop); +event_t *epg_event_create(channel_t *ch, time_t start, time_t stop, + int dvb_id); event_t *epg_event_find_by_time(channel_t *ch, time_t t); diff --git a/src/xmltv.c b/src/xmltv.c index 247d7db5..db03b1ea 100644 --- a/src/xmltv.c +++ b/src/xmltv.c @@ -334,7 +334,7 @@ xmltv_parse_programme_tags(xmltv_channel_t *xc, htsmsg_t *tags, const char *desc = xmltv_get_cdata_by_tag(tags, "desc"); LIST_FOREACH(ch, &xc->xc_channels, ch_xc_link) { - if((e = epg_event_create(ch, start, stop)) == NULL) + if((e = epg_event_create(ch, start, stop, -1)) == NULL) continue; if(title != NULL) epg_event_set_title(e, title);