]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Revamp EPG framework. Much simpler (and faster) now.
authorAndreas Öman <andreas@lonelycoder.com>
Tue, 2 Sep 2008 20:32:54 +0000 (20:32 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Tue, 2 Sep 2008 20:32:54 +0000 (20:32 +0000)
Makefile
channels.c
dvb/dvb_tables.c
epg.c
epg.h
pvr.c
tvhead.h

index 639628d51935f9633195c24d0c95447868dea6ce..33c9c0f2e7770808cba8fddb73fb52e6ee11bae8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 -include ../config.mak
 
-SRCS = main.c access.c dtable.c tcp.c http.c notify.c
+SRCS = main.c access.c dtable.c tcp.c http.c notify.c epg.c
 
 SRCS += buffer.c channels.c subscriptions.c transports.c
 
index db89b1266e03957af51af2661ad99a6ad688e427..c41cd5569b2bcd9edcc1cd20e6ed74ce7c58fae8 100644 (file)
@@ -146,7 +146,7 @@ channel_create(const char *name)
   }
 
   ch = calloc(1, sizeof(channel_t));
-  TAILQ_INIT(&ch->ch_epg_events);
+  RB_INIT(&ch->ch_epg_events);
 
   channel_set_name(ch, name);
 
index bcff69a36bb9fedb2368a026ac67d1a075be9905..5d9f1a94290ae5fa50fa8ffe1b34afc23d76b855 100644 (file)
@@ -308,6 +308,10 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
   char desc[5000];
   epg_content_type_t *ect;
 
+  event_t *e;
+
+  lock_assert(&global_lock);
+
   //  printf("EIT!, tid = %x\n", tableid);
 
   if(tableid < 0x4e || tableid > 0x6f || len < 11)
@@ -356,6 +360,9 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
     if(dllen > len)
       break;
 
+    e = epg_event_find_by_start(ch, start_time, 1);
+    e->e_duration = duration;
+
     ect = NULL;
     *title = 0;
     *desc = 0;
@@ -370,28 +377,25 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
 
       switch(dtag) {
       case DVB_DESC_SHORT_EVENT:
-       if(dvb_desc_short_event(ptr, dlen,
-                               title, sizeof(title),
-                               desc,  sizeof(desc)) < 0)
-         duration = 0;
+       if(!dvb_desc_short_event(ptr, dlen,
+                                title, sizeof(title),
+                                desc,  sizeof(desc))) {
+         epg_event_set_title(e, title);
+         epg_event_set_desc(e, desc);
+       }
        break;
 
       case DVB_DESC_CONTENT:
        if(dlen >= 2) {
          /* We only support one content type per event atm. */
-         //      ect = epg_content_type_find_by_dvbcode(*ptr);
+         ect = epg_content_type_find_by_dvbcode(*ptr);
+         epg_event_set_content_type(e, ect);
        }
        break;
       }
 
       len -= dlen; ptr += dlen; dllen -= dlen;
     }
-
-    if(duration > 0) {
-      //epg_update_event_by_id(ch, event_id, start_time, duration,
-      //title, desc, ect);
-      
-    }
   }
 }
 
diff --git a/epg.c b/epg.c
index 139a28368a0e8f5bdddcd92271e44b403d67e5b3..f692b7a9eafd9a261ce9127d77f106cb456e36d5 100644 (file)
--- a/epg.c
+++ b/epg.c
 #include "tvhead.h"
 #include "channels.h"
 #include "epg.h"
-#include "dispatch.h"
-#include "htsp.h"
-#include "autorec.h"
 
 #define EPG_MAX_AGE 86400
 
-#define EPG_HASH_ID_WIDTH 256
+epg_content_group_t *epg_content_groups[16];
 
-struct event_list epg_hash[EPG_HASH_ID_WIDTH];
-static dtimer_t epg_channel_maintain_timer;
+static int
+e_ch_cmp(const event_t *a, const event_t *b)
+{
+  return a->e_start - b->e_start;
+}
 
-epg_content_group_t *epg_content_groups[16];
 
+/**
+ *
+ */
 void
 epg_event_set_title(event_t *e, const char *title)
 {
+  printf("title=%s\n", title);
   free((void *)e->e_title);
   e->e_title = strdup(title);
 }
 
+
+/**
+ *
+ */
 void
 epg_event_set_desc(event_t *e, const char *desc)
 {
@@ -52,7 +59,11 @@ epg_event_set_desc(event_t *e, const char *desc)
   e->e_desc = strdup(desc);
 }
 
-static void
+
+/**
+ *
+ */
+void
 epg_event_set_content_type(event_t *e, epg_content_type_t *ect)
 {
   if(e->e_content_type != NULL)
@@ -63,99 +74,61 @@ epg_event_set_content_type(event_t *e, epg_content_type_t *ect)
     LIST_INSERT_HEAD(&ect->ect_events, e, e_content_type_link);
 }
 
-event_t *
-epg_event_find_by_time0(struct event_queue *q, time_t start)
-{
-  event_t *e;
-
-  TAILQ_FOREACH(e, q, e_channel_link)
-    if(start >= e->e_start && start < e->e_start + e->e_duration)
-      break;
-  return e;
-}
-
-event_t *
-epg_event_find_by_time(channel_t *ch, time_t start)
-{
-  return epg_event_find_by_time0(&ch->ch_epg_events, start);
-}
-
-event_t *
-epg_event_find_by_tag(uint32_t tag)
-{
-  event_t *e;
-  unsigned int l = tag % EPG_HASH_ID_WIDTH;
-
-  LIST_FOREACH(e, &epg_hash[l], e_hash_link)
-    if(e->e_tag == tag)
-      break;
-
-  return e;
-}
-
 
+/**
+ *
+ */
 event_t *
-epg_event_get_current(channel_t *ch)
+epg_event_find_by_start(channel_t *ch, time_t start, int create)
 {
-  event_t *e;
+  static event_t *skel, *e;
 
-  time_t now;
-  time(&now);
+  lock_assert(&global_lock);
 
-  e = ch->ch_epg_cur_event;
-  if(e == NULL || now < e->e_start || now > e->e_start + e->e_duration)
-    return NULL;
+  if(skel == NULL)
+    skel = calloc(1, sizeof(event_t));
 
-  return e;
-}
+  skel->e_start = start;
 
-event_t *
-epg_event_find_current_or_upcoming(channel_t *ch)
-{
-  event_t *e;
+  if(!create)
+    return RB_FIND(&ch->ch_epg_events, skel, e_channel_link, e_ch_cmp);
 
-  TAILQ_FOREACH(e, &ch->ch_epg_events, e_channel_link)
-    if(e->e_start + e->e_duration > dispatch_clock)
-      break;
+  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;
+  }
   return e;
 }
 
 
-static int
-startcmp(event_t *a, event_t *b)
-{
-  return a->e_start - b->e_start;
-}
-
+/**
+ *
+ */
 event_t *
-epg_event_build(struct event_queue *head, time_t start, int duration)
+epg_event_find_by_time(channel_t *ch, time_t t)
 {
-  time_t now;
-  event_t *e;
-
-  time(&now);
+  event_t skel, *e;
 
-  if(duration < 1 || start + duration < now - EPG_MAX_AGE)
+  skel.e_start = t;
+  e = RB_FIND_LE(&ch->ch_epg_events, &skel, e_channel_link, e_ch_cmp);
+  if(e == NULL || e->e_start + e->e_duration < t)
     return NULL;
-
-  TAILQ_FOREACH(e, head, e_channel_link)
-    if(start == e->e_start && duration == e->e_duration)
-      return e;
-  e = calloc(1, sizeof(event_t));
-
-  e->e_duration = duration;
-  e->e_start = start;
-  TAILQ_INSERT_SORTED(head, e, e_channel_link, startcmp);
-
   return e;
 }
 
 
-
+/**
+ *
+ */
 void
-epg_event_free(event_t *e)
+epg_event_destroy(event_t *e)
 {
+  channel_t *ch = e->e_channel;
+
+  RB_REMOVE(&ch->ch_epg_events, e, e_channel_link);
+  
   if(e->e_content_type != NULL)
     LIST_REMOVE(e, e_content_type_link);
 
@@ -164,245 +137,12 @@ epg_event_free(event_t *e)
   free(e);
 }
 
-
-
-static void
-epg_event_destroy(channel_t *ch, event_t *e)
-{
-  //  printf("epg: flushed event %s\n", e->e_title);
-
-  if(ch->ch_epg_cur_event == e)
-    ch->ch_epg_cur_event = NULL;
-
-  TAILQ_REMOVE(&ch->ch_epg_events, e, e_channel_link);
-  LIST_REMOVE(e, e_hash_link);
-
-  epg_event_free(e);
-}
-
-
-void
-event_time_txt(time_t start, int duration, char *out, int outlen)
-{
-  char tmp1[40];
-  char tmp2[40];
-  char *c;
-  time_t stop = start + duration;
-
-  ctime_r(&start, tmp1);
-  c = strchr(tmp1, '\n');
-  if(c)
-    *c = 0;
-
-  ctime_r(&stop, tmp2);
-  c = strchr(tmp2, '\n');
-  if(c)
-    *c = 0;
-
-  snprintf(out, outlen, "[%s - %s]", tmp1, tmp2);
-}
-
-
-static int
-check_overlap0(channel_t *ch, event_t *a)
-{
-  char atime[100];
-  char btime[100];
-  event_t *b;
-  int overshot;
-
-  b = TAILQ_NEXT(a, e_channel_link);
-  if(b == NULL)
-    return 0;
-
-  overshot = a->e_start + a->e_duration - b->e_start;
-
-  if(overshot < 1)
-    return 0;
-
-  event_time_txt(a->e_start, a->e_duration, atime, sizeof(atime));
-  event_time_txt(b->e_start, b->e_duration, btime, sizeof(btime));
-
-  if(a->e_source > b->e_source) {
-
-    b->e_start += overshot;
-    b->e_duration -= overshot;
-    
-    if(b->e_duration < 1) {
-      epg_event_destroy(ch, b);
-      return 1;
-    }
-  } else {
-    a->e_duration -= overshot;
-
-    if(a->e_duration < 1) {
-      epg_event_destroy(ch, a);
-      return 1;
-    }
-  }
-  return 0;
-}
-
-static int
-check_overlap(channel_t *ch, event_t *e)
-{
-  event_t *p;
-
-  p = TAILQ_PREV(e, event_queue, e_channel_link);
-  if(p != NULL) {
-    if(check_overlap0(ch, p))
-      return 1;
-  }
-
-  return check_overlap0(ch, e);
-}
-
-
-
-
-static void
-epg_event_create(channel_t *ch, time_t start, int duration, 
-                const char *title, const char *desc, int source, 
-                uint16_t id, epg_content_type_t *ect)
-{
-  unsigned int l;
-  time_t now;
-  event_t *e;
-
-  time(&now);
-
-  if(duration < 1 || start + duration < now - EPG_MAX_AGE)
-    return;
-
-  TAILQ_FOREACH(e, &ch->ch_epg_events, e_channel_link) {
-    if(start == e->e_start && duration == e->e_duration)
-      break;
-
-    if(start == e->e_start && !strcmp(e->e_title ?: "", title))
-      break;
-  }
-
-  if(e == NULL) {
-    e = calloc(1, sizeof(event_t));
-
-    e->e_start = start;
-    TAILQ_INSERT_SORTED(&ch->ch_epg_events, e, e_channel_link, startcmp);
-
-    e->e_channel = ch;
-    e->e_event_id = id;
-    e->e_duration = duration;
-
-    e->e_tag = tag_get();
-    l = e->e_tag % EPG_HASH_ID_WIDTH;
-    LIST_INSERT_HEAD(&epg_hash[l], e, e_hash_link);
-  }
-
-  if(source > e->e_source) {
-
-    e->e_source = source;
-
-    if(e->e_duration != duration) {
-      char before[100];
-      char after[100];
-
-      event_time_txt(e->e_start, e->e_duration, before, sizeof(before));
-      event_time_txt(e->e_start, duration, after, sizeof(after));
-
-      e->e_duration = duration;
-    }
-
-    if(title != NULL) epg_event_set_title(e, title);
-    if(desc  != NULL) epg_event_set_desc(e, desc);
-    if(ect   != NULL) epg_event_set_content_type(e, ect);
-  }
-  
-  check_overlap(ch, e);
-}
-
-
-
-
+#if 0
+/**
+ *
+ */
 void
-epg_update_event_by_id(channel_t *ch, uint16_t event_id, 
-                      time_t start, int duration, const char *title,
-                      const char *desc, epg_content_type_t *ect)
-{
-  event_t *e;
-
-  TAILQ_FOREACH(e, &ch->ch_epg_events, e_channel_link)
-    if(e->e_event_id == event_id)
-      break;
-
-  if(e != NULL) {
-    /* We already have information about this event */
-
-     if(e->e_duration != duration || e->e_start != start) {
-
-      char before[100];
-      char after[100];
-
-      event_time_txt(e->e_start, e->e_duration, before, sizeof(before));
-      event_time_txt(start, duration, after, sizeof(after));
-       
-      TAILQ_REMOVE(&ch->ch_epg_events, e, e_channel_link);
-
-      e->e_duration = duration;
-      e->e_start = start;
-      TAILQ_INSERT_SORTED(&ch->ch_epg_events, e, e_channel_link, startcmp);
-
-      if(check_overlap(ch, e))
-       return; /* event was destroyed, return at once */
-    }
-
-    epg_event_set_title(e, title);
-    epg_event_set_desc(e, desc);
-    epg_event_set_content_type(e, ect);
-
-  } else {
-  
-    epg_event_create(ch, start, duration, title, desc,
-                    EVENT_SRC_DVB, event_id, ect);
-  }
-}
-
-
-static void
-epg_set_current_event(channel_t *ch, event_t *e)
-{
-  if(e == ch->ch_epg_cur_event)
-    return;
-
-  ch->ch_epg_cur_event = e;
-
-  /* Notify clients that a new programme is on */
-
-  htsp_async_channel_update(ch);
-
-  if(e == NULL)
-    return;
-  /* Let autorecorder check this event */
-  autorec_check_new_event(e);
-
-  e = TAILQ_NEXT(e, e_channel_link);
-  /* .. and next one, to make better scheduling */
-
-  if(e != NULL)
-    autorec_check_new_event(e);
-}
-
-static void
-epg_locate_current_event(channel_t *ch, time_t now)
-{
-  event_t *e;
-  e = epg_event_find_by_time(ch, now);
-  epg_set_current_event(ch, e);
-}
-
-
-
-static void
-epg_channel_maintain(void *aux, int64_t clk)
+epg_channel_maintain()
 {
   channel_t *ch;
   event_t *e, *cur;
@@ -440,6 +180,7 @@ epg_channel_maintain(void *aux, int64_t clk)
     epg_locate_current_event(ch, now);
   }
 }
+#endif
 
 
 /**
@@ -450,33 +191,15 @@ epg_destroy_by_channel(channel_t *ch)
 {
   event_t *e;
 
-  while((e = TAILQ_FIRST(&ch->ch_epg_events)) != NULL)
-    epg_event_destroy(ch, e);
+  while((e = ch->ch_epg_events.root) != NULL)
+    epg_event_destroy(e);
 }
 
 
+
 /**
  *
  */
-void
-epg_transfer_events(channel_t *ch, struct event_queue *src, 
-                   const char *srcname, char *icon)
-{
-  event_t *e;
-  int cnt = 0;
-
-  if(strcmp(icon ?: "", ch->ch_icon ?: ""))
-    channel_set_icon(ch, icon);
-
-  TAILQ_FOREACH(e, src, e_channel_link) {
-
-    epg_event_create(ch, e->e_start, e->e_duration, e->e_title,
-                    e->e_desc, EVENT_SRC_XMLTV, 0,
-                    e->e_content_type);
-    cnt++;
-  }
-}
-
 static const char *groupnames[16] = {
   [0] = "Unclassified",
   [1] = "Movie / Drama",
@@ -544,6 +267,7 @@ epg_content_group_find_by_name(const char *name)
  *
  * XXX: Optimize if we know channel, group, etc
  */
+#if 0
 int
 epg_search(struct event_list *h, const char *title, 
           epg_content_group_t *s_ecg,
@@ -592,6 +316,7 @@ epg_search(struct event_list *h, const char *title,
 
   return num;
 }
+#endif
 
 /*
  *
@@ -603,7 +328,5 @@ epg_init(void)
 
   for(i = 0x0; i < 0x100; i+=16)
     epg_content_type_find_by_dvbcode(i);
-
-  dtimer_arm(&epg_channel_maintain_timer, epg_channel_maintain, NULL, 5);
 }
 
diff --git a/epg.h b/epg.h
index 86e4e3ebebc9d295b58077d7e2a6f136b8c6c1c8..df59ea7ff86570b08ca2a0dc7cc8b6f89a442c86 100644 (file)
--- a/epg.h
+++ b/epg.h
 #ifndef EPG_H
 #define EPG_H
 
-extern epg_content_group_t *epg_content_groups[16];
-
 void epg_init(void);
 
-event_t *epg_event_find_by_time0(struct event_queue *q, time_t start);
-
-event_t *epg_event_find_by_time(channel_t *ch, time_t start);
-
-event_t *epg_event_find_by_tag(uint32_t id);
-
-event_t *epg_event_get_current(channel_t *ch);
-
-event_t *epg_event_build(struct event_queue *head, time_t start, int duration);
-
-void epg_event_free(event_t *e);
 
 void epg_event_set_title(event_t *e, const char *title);
 
 void epg_event_set_desc(event_t *e, const char *desc);
 
-void epg_update_event_by_id(channel_t *ch, uint16_t event_id, 
-                           time_t start, int duration, const char *title,
-                           const char *desc, epg_content_type_t *ect);
+void epg_event_set_content_type(event_t *e, epg_content_type_t *ect);
 
-void epg_transfer_events(channel_t *ch, struct event_queue *src, 
-                        const char *srcname, char *icon);
+event_t *epg_event_find_by_start(channel_t *ch, time_t start, int create);
 
-void event_time_txt(time_t start, int duration, char *out, int outlen);
+event_t *epg_event_find_by_time(channel_t *ch, time_t t);
 
-event_t *epg_event_find_current_or_upcoming(channel_t *ch);
+void epg_event_destroy(event_t *e);
 
-epg_content_type_t *epg_content_type_find_by_dvbcode(uint8_t dvbcode);
+void epg_destroy_by_channel(channel_t *ch);
 
-epg_content_group_t *epg_content_group_find_by_name(const char *name);
 
-int epg_search(struct event_list *h, const char *title,
-              epg_content_group_t *s_ecg, channel_t *s_ch);
+/**
+ *
+ */
+epg_content_type_t *epg_content_type_find_by_dvbcode(uint8_t dvbcode);
 
-void epg_destroy_by_channel(channel_t *ch);
+epg_content_group_t *epg_content_group_find_by_name(const char *name);
 
 #endif /* EPG_H */
diff --git a/pvr.c b/pvr.c
index 6dbcdedcd21c578a8edd71daf632a595e77e2520..af8b2d0633c5747a8cef907e62640ff71a3b1256 100644 (file)
--- a/pvr.c
+++ b/pvr.c
@@ -62,7 +62,7 @@ static void postrec(pvr_rec_t *pvrr);
 
 /**
  * Initialize PVR framework
- */
 */
 void
 pvr_init(void)
 {
index 67a801dfdfe3e6e70a94a6212fea16830002d715..d4377e6788909d56163f3c1e5d1585fb190e070d 100644 (file)
--- a/tvhead.h
+++ b/tvhead.h
@@ -87,7 +87,7 @@ TAILQ_HEAD(channel_queue, channel);
 TAILQ_HEAD(th_dvb_adapter_queue, th_dvb_adapter);
 LIST_HEAD(th_v4l_adapter_list, th_v4l_adapter);
 LIST_HEAD(event_list, event);
-TAILQ_HEAD(event_queue, event);
+RB_HEAD(event_tree, event);
 LIST_HEAD(pvr_rec_list, pvr_rec);
 TAILQ_HEAD(ref_update_queue, ref_update);
 LIST_HEAD(th_transport_list, th_transport);
@@ -778,7 +778,7 @@ typedef struct channel {
     COMMERCIAL_DETECT_TTP192,
   } ch_commercial_detection;
 
-  struct event_queue ch_epg_events;
+  struct event_tree ch_epg_events;
   struct event *ch_epg_cur_event;
   char *ch_icon;
 
@@ -868,10 +868,7 @@ typedef struct epg_content_type {
  */
 typedef struct event {
   channel_t *e_channel;
-  TAILQ_ENTRY(event) e_channel_link;
-
-  LIST_ENTRY(event) e_hash_link;
-  LIST_ENTRY(event) e_tmp_link;
+  RB_ENTRY(event) e_channel_link;
 
   LIST_ENTRY(event) e_content_type_link;
   epg_content_type_t *e_content_type;
@@ -882,10 +879,6 @@ typedef struct event {
   const char *e_title;   /* UTF-8 encoded */
   const char *e_desc;    /* UTF-8 encoded */
 
-  uint16_t e_event_id;  /* DVB event id */
-
-  uint32_t e_tag;
-
   int e_source; /* higer is better, and we never downgrade */
 
 #define EVENT_SRC_XMLTV 1