* 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
This commit is contained in:
Andreas Öman 2009-07-18 20:07:47 +00:00
parent 2fcb7fe72b
commit be1a42d909
5 changed files with 147 additions and 115 deletions

7
debian/changelog vendored
View file

@ -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

View file

@ -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;

242
src/epg.c
View file

@ -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;
}
/**
*
*/

View file

@ -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);

View file

@ -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);