summaryrefslogtreecommitdiff
path: root/eit.c
diff options
context:
space:
mode:
Diffstat (limited to 'eit.c')
-rw-r--r--eit.c1443
1 files changed, 1096 insertions, 347 deletions
diff --git a/eit.c b/eit.c
index 44c873b..65856e6 100644
--- a/eit.c
+++ b/eit.c
@@ -13,20 +13,606 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.c 1.4 2000/10/01 14:09:05 kls Exp $
+ * $Id: eit.c 1.7 2000/11/02 17:06:19 kls Exp $
***************************************************************************/
#include "eit.h"
+#include <ctype.h>
+#include <dvb_comcode.h>
+#include <dvb_v4l.h>
+#include <fcntl.h>
+#include <fstream.h>
+#include <iomanip.h>
#include <iostream.h>
+#include <minmax.h>
#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
-#include <dvb_comcode.h>
-#include "tools.h"
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+// --- cMJD ------------------------------------------------------------------
+
+class cMJD {
+public:
+ cMJD();
+ cMJD(u_char date_hi, u_char date_lo);
+ cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese);
+ ~cMJD();
+ /** */
+ void ConvertToTime();
+ /** */
+ bool SetSystemTime();
+ /** */
+ time_t GetTime_t();
+protected: // Protected attributes
+ /** */
+ time_t mjdtime;
+protected: // Protected attributes
+ /** */
+ u_char time_second;
+protected: // Protected attributes
+ /** */
+ u_char time_minute;
+protected: // Protected attributes
+ /** */
+ u_char time_hour;
+protected: // Protected attributes
+ /** */
+ u_short mjd;
+};
+
+cMJD::cMJD()
+{
+}
+
+cMJD::cMJD(u_char date_hi, u_char date_lo)
+{
+ mjd = date_hi << 8 | date_lo;
+ time_hour = time_minute = time_second = 0;
+ ConvertToTime();
+}
+
+cMJD::cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese)
+{
+ mjd = date_hi << 8 | date_lo;
+ time_hour = timehr;
+ time_minute = timemi;
+ time_second = timese;
+ ConvertToTime();
+}
+
+cMJD::~cMJD()
+{
+}
+
+/** */
+void cMJD::ConvertToTime()
+{
+ struct tm t;
+
+ t.tm_sec = time_second;
+ t.tm_min = time_minute;
+ t.tm_hour = time_hour;
+ int k;
+
+ t.tm_year = (int) ((mjd - 15078.2) / 365.25);
+ t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001);
+ t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001));
+ k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0;
+ t.tm_year = t.tm_year + k;
+ t.tm_mon = t.tm_mon - 1 - k * 12;
+ t.tm_mon--;
+
+ t.tm_isdst = -1;
+ t.tm_gmtoff = 0;
+
+ mjdtime = timegm(&t);
+
+ //isyslog(LOG_INFO, "Time parsed = %s\n", ctime(&mjdtime));
+}
+
+/** */
+bool cMJD::SetSystemTime()
+{
+ struct tm *ptm;
+ time_t loctim;
+
+ ptm = localtime(&mjdtime);
+ loctim = time(NULL);
+
+ if (abs(mjdtime - loctim) > 2)
+ {
+ isyslog(LOG_INFO, "System Time = %s (%ld)\n", ctime(&loctim), loctim);
+ isyslog(LOG_INFO, "Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime);
+ if (stime(&mjdtime) < 0)
+ esyslog(LOG_ERR, "ERROR while setting system time: %s", strerror(errno));
+ return true;
+ }
+
+ return false;
+}
+/** */
+time_t cMJD::GetTime_t()
+{
+ return mjdtime;
+}
+
+// --- cTDT ------------------------------------------------------------------
typedef struct {
+ u_char table_id : 8;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char section_syntax_indicator : 1;
+ u_char : 3;
+ u_char section_length_hi : 4;
+#else
+ u_char section_length_hi : 4;
+ u_char : 3;
+ u_char section_syntax_indicator : 1;
+#endif
+
+ u_char section_length_lo : 8;
+
+
+ u_char utc_date_hi : 8;
+ u_char utc_date_lo : 8;
+ u_char utc_hour : 4;
+ u_char utc_hour_ten : 4;
+ u_char utc_min : 4;
+ u_char utc_min_ten : 4;
+ u_char utc_sec : 4;
+ u_char utc_sec_ten : 4;
+} tdt_t;
+
+class cTDT {
+public:
+ cTDT(tdt_t *ptdt);
+ ~cTDT();
+ /** */
+ bool SetSystemTime();
+protected: // Protected attributes
+ /** */
+ tdt_t tdt;
+ /** */
+ cMJD * mjd;
+};
+
+cTDT::cTDT(tdt_t *ptdt)
+{
+ tdt = *ptdt;
+ mjd = new cMJD(tdt.utc_date_hi, tdt.utc_date_lo,
+ tdt.utc_hour_ten * 10 + tdt.utc_hour,
+ tdt.utc_min_ten * 10 + tdt.utc_min,
+ tdt.utc_sec_ten * 10 + tdt.utc_sec);
+}
+
+cTDT::~cTDT()
+{
+}
+/** */
+bool cTDT::SetSystemTime()
+{
+ return mjd->SetSystemTime();
+}
+
+// --- cEventInfo ------------------------------------------------------------
+
+cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid)
+{
+ pTitle = NULL;
+ pSubtitle = NULL;
+ pExtendedDescription = NULL;
+ bIsPresent = bIsFollowing = false;
+ lDuration = 0;
+ tTime = 0;
+ uEventID = eventid;
+ uServiceID = serviceid;
+ cExtendedDescriptorNumber = 0;
+ nChannelNumber = 0;
+}
+
+cEventInfo::~cEventInfo()
+{
+ delete pTitle;
+ delete pSubtitle;
+ delete pExtendedDescription;
+}
+
+/** */
+const char * cEventInfo::GetTitle() const
+{
+ return pTitle;
+}
+/** */
+const char * cEventInfo::GetSubtitle() const
+{
+ return pSubtitle;
+}
+/** */
+const char * cEventInfo::GetExtendedDescription() const
+{
+ return pExtendedDescription;
+}
+/** */
+bool cEventInfo::IsPresent() const
+{
+ return bIsPresent;
+}
+/** */
+void cEventInfo::SetPresent(bool pres)
+{
+ bIsPresent = pres;
+}
+/** */
+bool cEventInfo::IsFollowing() const
+{
+ return bIsFollowing;
+}
+/** */
+void cEventInfo::SetFollowing(bool foll)
+{
+ bIsFollowing = foll;
+}
+/** */
+const char * cEventInfo::GetDate() const
+{
+ static char szDate[25];
+
+ strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime(&tTime));
+
+ return szDate;
+}
+/** */
+const char * cEventInfo::GetTimeString() const
+{
+ static char szTime[25];
+
+ strftime(szTime, sizeof(szTime), "%R", localtime(&tTime));
+
+ return szTime;
+}
+/** */
+const char * cEventInfo::GetEndTimeString() const
+{
+ static char szEndTime[25];
+ time_t tEndTime = tTime + lDuration;
+
+ strftime(szEndTime, sizeof(szEndTime), "%R", localtime(&tEndTime));
+
+ return szEndTime;
+}
+/** */
+time_t cEventInfo::GetTime() const
+{
+ return tTime;
+}
+/** */
+long cEventInfo::GetDuration() const
+{
+ return lDuration;
+}
+/** */
+unsigned short cEventInfo::GetEventID() const
+{
+ return uEventID;
+}
+/** */
+bool cEventInfo::SetTitle(char *string)
+{
+ if (string == NULL)
+ return false;
+
+ pTitle = strdup(string);
+ if (pTitle == NULL)
+ return false;
+
+ return true;
+}
+/** */
+bool cEventInfo::SetSubtitle(char *string)
+{
+ if (string == NULL)
+ return false;
+
+ pSubtitle = strdup(string);
+ if (pSubtitle == NULL)
+ return false;
+
+ return true;
+}
+/** */
+bool cEventInfo::AddExtendedDescription(char *string)
+{
+ int size = 0;
+ bool first = true;
+ char *p;
+
+ if (string == NULL)
+ return false;
+
+ if (pExtendedDescription)
+ {
+ first = false;
+ size += strlen(pExtendedDescription);
+ }
+
+ size += (strlen(string) + 1);
+
+ p = (char *)realloc(pExtendedDescription, size);
+ if (p == NULL)
+ return false;
+
+ if (first)
+ *p = 0;
+
+ strcat(p, string);
+
+ pExtendedDescription = p;
+
+ return true;
+}
+/** */
+void cEventInfo::SetTime(time_t t)
+{
+ tTime = t;
+}
+/** */
+void cEventInfo::SetDuration(long l)
+{
+ lDuration = l;
+}
+/** */
+void cEventInfo::SetEventID(unsigned short evid)
+{
+ uEventID = evid;
+}
+/** */
+void cEventInfo::SetServiceID(unsigned short servid)
+{
+ uServiceID = servid;
+}
+/** */
+u_char cEventInfo::GetExtendedDescriptorNumber() const
+{
+ return cExtendedDescriptorNumber;
+}
+/** */
+void cEventInfo::IncreaseExtendedDescriptorNumber()
+{
+ cExtendedDescriptorNumber++;
+}
+
+/** */
+unsigned short cEventInfo::GetServiceID() const
+{
+ return uServiceID;
+}
+
+// --- cSchedule -------------------------------------------------------------
+
+cSchedule::cSchedule(unsigned short servid)
+{
+ pPresent = pFollowing = NULL;
+ uServiceID = servid;
+}
+
+
+cSchedule::~cSchedule()
+{
+}
+/** */
+const cEventInfo * cSchedule::GetPresentEvent() const
+{
+ // checking temporal sanity of present event (kls 2000-11-01)
+ time_t now = time(NULL);
+ if (pPresent && !(pPresent->GetTime() <= now && now <= pPresent->GetTime() + pPresent->GetDuration()))
+ {
+ cEventInfo *pe = Events.First();
+ while (pe != NULL)
+ {
+ if (pe->GetTime() <= now && now <= pe->GetTime() + pe->GetDuration())
+ return pe;
+ pe = Events.Next(pe);
+ }
+ }
+ return pPresent;
+}
+/** */
+const cEventInfo * cSchedule::GetFollowingEvent() const
+{
+ // checking temporal sanity of following event (kls 2000-11-01)
+ time_t now = time(NULL);
+ const cEventInfo *pr = GetPresentEvent(); // must have it verified!
+ if (pFollowing && !(pr && pr->GetTime() + pr->GetDuration() <= pFollowing->GetTime()))
+ {
+ int minDt = INT_MAX;
+ cEventInfo *pe = Events.First(), *pf = NULL;
+ while (pe != NULL)
+ {
+ int dt = pe->GetTime() - now;
+ if (dt > 0 && dt < minDt)
+ {
+ minDt = dt;
+ pf = pe;
+ }
+ pe = Events.Next(pe);
+ }
+ return pf;
+ }
+ return pFollowing;
+}
+/** */
+void cSchedule::SetServiceID(unsigned short servid)
+{
+ uServiceID = servid;
+}
+/** */
+unsigned short cSchedule::GetServiceID() const
+{
+ return uServiceID;
+}
+/** */
+const cEventInfo * cSchedule::GetEvent(unsigned short uEventID) const
+{
+ cEventInfo *pe = Events.First();
+ while (pe != NULL)
+ {
+ if (pe->GetEventID() == uEventID)
+ return pe;
+
+ pe = Events.Next(pe);
+ }
+
+ return NULL;
+}
+/** */
+const cEventInfo * cSchedule::GetEvent(time_t tTime) const
+{
+ cEventInfo *pe = Events.First();
+ while (pe != NULL)
+ {
+ if (pe->GetTime() == tTime)
+ return pe;
+
+ pe = Events.Next(pe);
+ }
+
+ return NULL;
+}
+/** */
+bool cSchedule::SetPresentEvent(cEventInfo *pEvent)
+{
+ if (pPresent != NULL)
+ pPresent->SetPresent(false);
+ pPresent = pEvent;
+ pPresent->SetPresent(true);
+
+ return true;
+}
+
+/** */
+bool cSchedule::SetFollowingEvent(cEventInfo *pEvent)
+{
+ if (pFollowing != NULL)
+ pFollowing->SetFollowing(false);
+ pFollowing = pEvent;
+ pFollowing->SetFollowing(true);
+
+ return true;
+}
+
+/** */
+void cSchedule::Cleanup()
+{
+ Cleanup(time(NULL));
+}
+
+/** */
+void cSchedule::Cleanup(time_t tTime)
+{
+ cEventInfo *pEvent;
+ for (int a = 0; true ; a++)
+ {
+ pEvent = Events.Get(a);
+ if (pEvent == NULL)
+ break;
+ if (pEvent->GetTime() + pEvent->GetDuration() < tTime)
+ {
+ Events.Del(pEvent);
+ a--;
+ }
+ }
+}
+
+// --- cSchedules ------------------------------------------------------------
+
+cSchedules::cSchedules()
+{
+ pCurrentSchedule = NULL;
+ uCurrentServiceID = 0;
+}
+
+cSchedules::~cSchedules()
+{
+}
+/** */
+bool cSchedules::SetCurrentServiceID(unsigned short servid)
+{
+ pCurrentSchedule = GetSchedule(servid);
+ if (pCurrentSchedule == NULL)
+ {
+ Add(new cSchedule(servid));
+ pCurrentSchedule = GetSchedule(servid);
+ if (pCurrentSchedule == NULL)
+ return false;
+ }
+
+ uCurrentServiceID = servid;
+
+ return true;
+}
+/** */
+const cSchedule * cSchedules::GetSchedule() const
+{
+ return pCurrentSchedule;
+}
+/** */
+const cSchedule * cSchedules::GetSchedule(unsigned short servid) const
+{
+ cSchedule *p;
+
+ p = First();
+ while (p != NULL)
+ {
+ if (p->GetServiceID() == servid)
+ return p;
+ p = Next(p);
+ }
+
+ return NULL;
+}
+
+/** */
+void cSchedules::Cleanup()
+{
+ cSchedule *p;
+
+ p = First();
+ while (p != NULL)
+ {
+ p->Cleanup(time(NULL));
+ p = Next(p);
+ }
+}
+
+// --- cEIT ------------------------------------------------------------------
+
+#define DEC(N) dec << setw(N) << setfill(int('0'))
+#define HEX(N) hex << setw(N) << setfill(int('0'))
+
+#define EIT_STUFFING_DESCRIPTOR 0x42
+#define EIT_LINKAGE_DESCRIPTOR 0x4a
+#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d
+#define EIT_EXTENDED_EVENT_DESCRIPTOR 0x4e
+#define EIT_TIME_SHIFTED_EVENT_DESCRIPTOR 0x4f
+#define EIT_COMPONENT_DESCRIPTOR 0x50
+#define EIT_CA_IDENTIFIER_DESCRIPTOR 0x53
+#define EIT_CONTENT_DESCRIPTOR 0x54
+#define EIT_PARENTAL_RATING_DESCRIPTOR 0x55
+#define EIT_TELEPHONE_DESCRIPTOR 0x57
+#define EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR 0x5e
+#define EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR 0x5f
+#define EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 0x61
+#define EIT_DATA_BROADCAST_DESCRIPTOR 0x64
+#define EIT_PDC_DESCRIPTOR 0x69
+
+typedef struct eit_struct {
u_char table_id : 8;
#if BYTE_ORDER == BIG_ENDIAN
@@ -64,9 +650,7 @@ typedef struct {
u_char segment_last_table_id : 8;
} eit_t;
-#define EIT_SIZE 14
-
-struct eit_loop_struct1 {
+typedef struct eit_loop_struct {
u_char event_id_hi : 8;
u_char event_id_lo : 8;
@@ -79,12 +663,12 @@ struct eit_loop_struct1 {
u_char time_second : 4;
u_char time_second_ten : 4;
- u_char dur_hour_ten : 4;
u_char dur_hour : 4;
- u_char dur_minute_ten : 4;
+ u_char dur_hour_ten : 4;
u_char dur_minute : 4;
- u_char dur_second_ten : 4;
+ u_char dur_minute_ten : 4;
u_char dur_second : 4;
+ u_char dur_second_ten : 4;
#if BYTE_ORDER == BIG_ENDIAN
u_char running_status : 3;
@@ -97,12 +681,9 @@ struct eit_loop_struct1 {
#endif
u_char descriptors_loop_length_lo : 8;
-};
+} eit_loop_t;
-#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d
-#define EIT_SHORT_EVENT_DESCRIPTOR_SIZE 6
-
-struct eit_short_event_descriptor_struct {
+typedef struct eit_short_event_struct {
u_char descriptor_tag : 8;
u_char descriptor_length : 8;
@@ -111,415 +692,583 @@ struct eit_short_event_descriptor_struct {
u_char language_code_3 : 8;
u_char event_name_length : 8;
-};
-
-#define EIT_EXTENDED_EVENT_DESCRIPOR 0x4e
-
-#define EIT_DESCRIPTOR_SIZE
-
-typedef struct eit_event_struct {
- u_char event_id_hi : 8;
- u_char event_id_lo : 8;
-
- u_char start_time_1 : 8;
- u_char start_time_2 : 8;
- u_char start_time_3 : 8;
- u_char start_time_4 : 8;
- u_char start_time_5 : 8;
-
- u_char duration_1 : 8;
- u_char duration_2 : 8;
- u_char duration_3 : 8;
-
-#if BYTE_ORDER == BIG_ENDIAN
- u_char running_status : 3;
- u_char free_CA_mode : 1;
- u_char descriptors_loop_length_hi : 4;
-#else
- u_char descriptors_loop_length_hi : 4;
- u_char free_CA_mode : 1;
- u_char running_status : 3;
-#endif
-
- u_char descriptors_loop_length_lo : 8;
-
-} eit_event_t;
-#define EIT_LOOP_SIZE 12
-
-
-typedef struct tot_t {
- u_char table_id : 8;
-
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator : 1;
- u_char : 3;
- u_char section_length_hi : 4;
-#else
- u_char section_length_hi : 4;
- u_char : 3;
- u_char section_syntax_indicator : 1;
-#endif
-
- u_char date_hi : 8;
- u_char date_lo : 8;
- u_char time_hour : 4;
- u_char time_hour_ten : 4;
- u_char time_minute : 4;
- u_char time_minute_ten : 4;
- u_char time_second : 4;
- u_char time_second_ten : 4;
-
-#if BYTE_ORDER == BIG_ENDIAN
- u_char : 4;
- u_char descriptor_loop_length_hi : 4;
-#else
- u_char descriptor_loop_length_hi : 4;
- u_char : 4;
-#endif
-
- u_char descriptor_loop_length_lo : 8;
-} tot_t;
-
-typedef struct local_time_offset {
+} eit_short_event_t;
+typedef struct eit_extended_event_struct {
u_char descriptor_tag : 8;
u_char descriptor_length : 8;
+ u_char last_descriptor_number : 4;
+ u_char descriptor_number : 4;
+
u_char language_code_1 : 8;
u_char language_code_2 : 8;
u_char language_code_3 : 8;
- u_char : 8;
-
- u_char offset_hour : 4;
- u_char offset_hour_ten : 4;
- u_char offset_minute : 4;
- u_char offset_minute_ten : 4;
+ u_char length_of_items : 8;
+} eit_extended_event_t;
+
+typedef struct eit_content_descriptor {
+ u_char descriptor_tag : 8;
+ u_char descriptor_length : 8;
+} eit_content_descriptor_t;
- u_char change_date_hi : 8;
- u_char change_date_lo : 8;
- u_char change_time_hour : 4;
- u_char change_time_hour_ten : 4;
- u_char change_time_minute : 4;
- u_char change_time_minute_ten : 4;
- u_char change_time_second : 4;
- u_char change_time_second_ten : 4;
+typedef struct eit_content_loop {
+ u_char content_nibble_level_2 : 4;
+ u_char content_nibble_level_1 : 4;
+ u_char user_nibble_2 : 4;
+ u_char user_nibble_1 : 4;
+} eit_content_loop_t;
- u_char next_offset_hour : 4;
- u_char next_offset_hour_ten : 4;
- u_char next_offset_minute : 4;
- u_char next_offset_minute_ten : 4;
-} local_time_offset;
+class cEIT {
+private:
+ cSchedules *schedules;
+public:
+ cEIT(void *buf, int length, cSchedules *Schedules);
+ ~cEIT();
+ /** */
+ int ProcessEIT();
-cEIT::cEIT()
+protected: // Protected methods
+ /** */
+ int strdvbcpy(unsigned char *dst, unsigned char *src, int max);
+ /** returns true if this EIT covers a
+present/following information, false if it's
+schedule information */
+ bool IsPresentFollowing();
+ /** */
+ bool WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf);
+ /** */
+ bool WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf);
+protected: // Protected attributes
+ int buflen;
+protected: // Protected attributes
+ /** */
+ u_char buffer[4097];
+ /** Table ID of this EIT struct */
+ u_char tid;
+ /** EITs service id (program number) */
+ u_short pid;
+};
+
+cEIT::cEIT(void * buf, int length, cSchedules *Schedules)
{
- cszBitFilter = "/dev/vbi";
- if((fsvbi = open(cszBitFilter, O_RDWR))<0)
- {
- fsvbi = 0;
- esyslog(LOG_ERR, "Failed to open DVB bitfilter device: %s", cszBitFilter);
- return;
- }
+ buflen = min((unsigned int)length, sizeof(buffer));
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, buf, buflen);
+ tid = buffer[0];
+ schedules = Schedules;
}
cEIT::~cEIT()
{
- if (fsvbi != 0)
- close(fsvbi);
- fsvbi = 0;
}
-/** Set the bitfilter in vbi device to return
-correct tables */
-int cEIT::SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode)
-{
- struct bitfilter filt = {
- pid,
- { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
- mode,0,
- FILTER_MEM,
- {},
- };
-
- if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0)
- return 0xffff;
- return 0;
-}
/** */
-int cEIT::GetSection(unsigned char *buf, ushort PID, unsigned char sec)
+int cEIT::ProcessEIT()
{
- int seclen=0;
- unsigned short handle, pid;
- unsigned char section, sectionnum=0xff, maxsec=0;
-
- if ((handle = SetBitFilter(PID, (sec<<8)|0x00ff, SECTION_CONTINUOS))==0xffff)
- return -1;
+ int bufact = 0;
+ eit_t *eit;
+ eit_loop_t *eitloop;
+ u_char tmp[256];
+
+ if (bufact + (int)sizeof(eit_t) > buflen)
+ return 0;
+ eit = (eit_t *)buffer;
+ bufact += sizeof(eit_t);
+
+ unsigned int service = (eit->service_id_hi << 8) | eit->service_id_lo;
+
+ while(bufact + (int)sizeof(eit_loop_t) <= buflen)
+ {
+ eitloop = (eit_loop_t *)&buffer[bufact];
+ bufact += sizeof(eit_loop_t);
+
+ int descdatalen = (eitloop->descriptors_loop_length_hi << 8) + eitloop->descriptors_loop_length_lo;
+ int descdataact = 0;
+
+ while (descdataact < descdatalen && bufact < buflen)
+ {
+ switch (buffer[bufact])
+ {
+ eit_content_descriptor_t *cont;
+ eit_content_loop_t *contloop;
+
+ case EIT_STUFFING_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_STUFFING_DESCRIPTOR");
+ break;
+
+ case EIT_LINKAGE_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_LINKAGE_DESCRIPTOR");
+ break;
+
+ case EIT_SHORT_EVENT_DESCRIPTOR:
+ WriteShortEventDescriptor(service, eitloop, &buffer[bufact]);
+ break;
- seclen=0;
- if (!cFile::AnyFileReady(fsvbi, 20000))
- {
- //cerr << "Timeout\n";
- return -1;
- }
+ case EIT_EXTENDED_EVENT_DESCRIPTOR:
+ WriteExtEventDescriptor(service, eitloop, &buffer[bufact]);
+ break;
+
+ case EIT_TIME_SHIFTED_EVENT_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_TIME_SHIFTED_EVENT_DESCRIPTOR");
+ break;
- read(fsvbi, buf, 8);
- seclen=(buf[6]<<8)|buf[7];
- pid=(buf[4]<<8)|buf[5];
+ case EIT_COMPONENT_DESCRIPTOR :
+ strdvbcpy(tmp, &buffer[bufact + 8], buffer[bufact + 1] - 6);
+ //dsyslog(LOG_INFO, "Found EIT_COMPONENT_DESCRIPTOR %c%c%c 0x%02x/0x%02x/0x%02x '%s'\n", buffer[bufact + 5], buffer[bufact + 6], buffer[bufact + 7], buffer[2], buffer[3], buffer[4], tmp);
+ break;
- read(fsvbi, buf, seclen);
- section=buf[0];
- sectionnum=buf[6];
- maxsec=buf[7];
+ case EIT_CA_IDENTIFIER_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_CA_IDENTIFIER_DESCRIPTOR");
+ break;
- //cerr << "secnum: " << HEX(2) << (int)sectionnum
- // << ", secmax: " << HEX(2) << (int) msecnum << "\n";
+ case EIT_CONTENT_DESCRIPTOR :
+ cont = (eit_content_descriptor_t *)buffer;
+ contloop = (eit_content_loop_t *)&buffer[sizeof(eit_content_descriptor_t)];
+ //dsyslog(LOG_INFO, "Found EIT_CONTENT_DESCRIPTOR 0x%02x/0x%02x\n", contloop->content_nibble_level_1, contloop->content_nibble_level_2);
+ break;
- CloseFilter(handle);
+ case EIT_PARENTAL_RATING_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_PARENTAL_RATING_DESCRIPTOR");
+ break;
- return seclen;
-}
+ case EIT_TELEPHONE_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_TELEPHONE_DESCRIPTOR");
+ break;
+
+ case EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_MULTILINGUAL_COMPONENT_DESCRIPTOR");
+ break;
+
+ case EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_PRIVATE_DATE_SPECIFIER_DESCRIPTOR");
+ break;
+
+ case EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_SHORT_SMOOTHING_BUFFER_DESCRIPTOR");
+ break;
+
+ case EIT_DATA_BROADCAST_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_DATA_BROADCAST_DESCRIPTOR");
+ break;
+
+ case EIT_PDC_DESCRIPTOR :
+ //dsyslog(LOG_INFO, "Found EIT_PDC_DESCRIPTOR");
+ break;
+
+ default:
+ //dsyslog(LOG_INFO, "Found unhandled descriptor 0x%02x with length of %04d\n", (int)buffer[bufact], (int)buffer[bufact + 1]);
+ break;
+ }
+ descdataact += (buffer[bufact + 1] + 2);
+ bufact += (buffer[bufact + 1] + 2);
+ }
+ }
-/** */
-int cEIT::CloseFilter(unsigned short handle)
-{
- if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &handle)<0)
- return -1;
return 0;
}
/** */
-char * cEIT::mjd2string(unsigned short mjd)
+int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max)
{
- int y, m, d, k;
- static char buf[20];
+ int a = 0;
- y = (int) ((mjd - 15078.2) / 365.25);
- m = (int) ((mjd - 14956.1 - (int)(y * 365.25)) / 30.6001);
- d = (int) (mjd - 14956 - (int)(y * 365.25) - (int)(m * 30.6001));
- k = (m == 14 || m == 15) ? 1 : 0;
- y = y + k;
- m = m - 1 - k * 12;
- sprintf(buf, "%d.%d.%4d", d, m, y + 1900);
+ if (*src == 0x05 || (*src >= 0x20 && *src <= 0xff))
+ {
+ for (a = 0; a < max; a++)
+ {
+ if (*src == 0)
+ break;
+
+ if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff))
+ *dst++ = *src++;
+ else
+ {
+ // if ((*src > '~' && *src < 0xa0) || *src == 0xff)
+ // cerr << "found special character 0x" << HEX(2) << (int)*src << endl;
+ src++;
+ }
+ }
+ *dst = 0;
+ }
+ else
+ {
+ const char *ret;
+
+ switch (*src)
+ {
+ case 0x01: ret = "Coding according to character table 1"; break;
+ case 0x02: ret = "Coding according to character table 2"; break;
+ case 0x03: ret = "Coding according to character table 3"; break;
+ case 0x04: ret = "Coding according to character table 4"; break;
+ case 0x10: ret = "Coding according to ISO/IEC 8859"; break;
+ case 0x11: ret = "Coding according to ISO/IEC 10646"; break;
+ case 0x12: ret = "Coding according to KSC 5601"; break;
+ default: ret = "Unknown coding"; break;
+ }
+ strncpy((char *)dst, ret, max);
+ }
+ return a;
+}
+
+/** returns true if this EIT covers a
+present/following information, false if it's
+schedule information */
+bool cEIT::IsPresentFollowing()
+{
+ if (tid == 0x4e || tid == 0x4f)
+ return true;
- return(buf);
+ return false;
}
/** */
-int cEIT::GetEIT()
+bool cEIT::WriteShortEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf)
{
- unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-)
- eit_t *eit;
- struct eit_loop_struct1 *eitloop;
- struct eit_short_event_descriptor_struct *eitevt;
- unsigned int seclen;
- unsigned short handle, pid;
- eit_event * pevt = (eit_event *)0;
- time_t tstart;
+ u_char tmp[256];
+ eit_short_event_t *evt = (eit_short_event_t *)buf;
+ unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo);
+ cEventInfo *pEvent;
+
+ //isyslog(LOG_INFO, "Found Short Event Descriptor");
- if ((handle = SetBitFilter(0x12, (0x4e << 8) | 0x00ff, SECTION_CONTINUOS))==0xffff)
+ cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service);
+ if (pSchedule == NULL)
{
- return -1;
+ schedules->Add(new cSchedule(service));
+ pSchedule = (cSchedule *)schedules->GetSchedule(service);
+ if (pSchedule == NULL)
+ return false;
}
-/*
- pid_t process = fork();
- if (process < 0)
+
+ /* cSchedule::GetPresentEvent() and cSchedule::GetFollowingEvent() verify
+ the temporal sanity of these events, so calling them here appears to
+ be a bad idea... (kls 2000-11-01)
+ //
+ // if we are working on a present/following info, let's see whether
+ // we already have present/following info for this service and if yes
+ // check whether it's the same eventid, if yes, just return, nothing
+ // left to do.
+ //
+ if (IsPresentFollowing())
{
- cerr << "GetEIT -1" << endl;
- return -1;
+ if (eitloop->running_status == 4 || eitloop->running_status == 3)
+ pEvent = (cEventInfo *)pSchedule->GetPresentEvent();
+ else
+ pEvent = (cEventInfo *)pSchedule->GetFollowingEvent();
+
+ if (pEvent != NULL)
+ if (pEvent->GetEventID() == eventid)
+ return true;
}
-
- if (process != 0)
+ */
+
+ //
+ // let's see whether we have that eventid already
+ // in case not, we have to create a new cEventInfo for it
+ //
+ pEvent = (cEventInfo *)pSchedule->GetEvent(eventid);
+ if (pEvent == NULL)
{
- cerr << "GetEIT 0" << endl;
- return 0;
+ pSchedule->Events.Add(new cEventInfo(service, eventid));
+ pEvent = (cEventInfo *)pSchedule->GetEvent(eventid);
+ if (pEvent == NULL)
+ return false;
+
+ strdvbcpy(tmp, &buf[sizeof(eit_short_event_t)], evt->event_name_length);
+ pEvent->SetTitle((char *)tmp);
+ strdvbcpy(tmp, &buf[sizeof(eit_short_event_t) + evt->event_name_length + 1],
+ (int)buf[sizeof(eit_short_event_t) + evt->event_name_length]);
+ pEvent->SetSubtitle((char *)tmp);
+ cMJD mjd(eitloop->date_hi, eitloop->date_lo,
+ eitloop->time_hour_ten * 10 + eitloop->time_hour,
+ eitloop->time_minute_ten * 10 + eitloop->time_minute,
+ eitloop->time_second_ten * 10 + eitloop->time_second);
+ pEvent->SetTime(mjd.GetTime_t());
+ pEvent->SetDuration((long)((long)((eitloop->dur_hour_ten * 10 + eitloop->dur_hour) * 60l * 60l) +
+ (long)((eitloop->dur_minute_ten * 10 + eitloop->dur_minute) * 60l) +
+ (long)(eitloop->dur_second_ten * 10 + eitloop->dur_second)));
}
-*/
- int nReceivedEITs = 0;
- tstart = time(NULL);
- while ((!evtRunning.bIsValid || !evtNext.bIsValid) && nReceivedEITs < 20 && difftime(time(NULL), tstart) < 4)
+
+ if (IsPresentFollowing())
{
- if (!cFile::AnyFileReady(fsvbi, 5000))
- {
- //cerr << "Timeout\n";
- CloseFilter(handle);
- return -1;
- }
+ if (eitloop->running_status == 4 || eitloop->running_status == 3)
+ pSchedule->SetPresentEvent(pEvent);
+ else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0)
+ pSchedule->SetFollowingEvent(pEvent);
+ }
+
+ return true;
+}
+
+/** */
+bool cEIT::WriteExtEventDescriptor(unsigned short service, eit_loop_t *eitloop, u_char *buf)
+{
+ u_char tmp[256];
+ eit_extended_event_t *evt = (eit_extended_event_t *)buf;
+ int bufact, buflen;
+ unsigned short eventid = (unsigned short)((eitloop->event_id_hi << 8) | eitloop->event_id_lo);
+ cEventInfo *pEvent;
- read(fsvbi, buf, 8);
- seclen=(buf[6]<<8)|buf[7];
- pid=(buf[4]<<8)|buf[5];
+ //isyslog(LOG_INFO, "Found Extended Event Descriptor");
- if (seclen >= sizeof(buf))
- seclen = sizeof(buf) - 1;
- read(fsvbi, buf, seclen);
+ cSchedule *pSchedule = (cSchedule *)schedules->GetSchedule(service);
+ if (pSchedule == NULL)
+ {
+ schedules->Add(new cSchedule(service));
+ pSchedule = (cSchedule *)schedules->GetSchedule(service);
+ if (pSchedule == NULL)
+ return false;
+ }
+
+ pEvent = (cEventInfo *)pSchedule->GetEvent(eventid);
+ if (pEvent == NULL)
+ return false;
- if (seclen < (int)(sizeof(eit_t)
- + sizeof(struct eit_loop_struct1)
- + sizeof(struct eit_short_event_descriptor_struct)))
- continue;
+ if (evt->descriptor_number != pEvent->GetExtendedDescriptorNumber())
+ return false;
- eit = (eit_t *)buf;
- eitloop = (struct eit_loop_struct1 *)&eit[1];
- eitevt = (struct eit_short_event_descriptor_struct *)&eitloop[1];
+ bufact = sizeof(eit_extended_event_t);
+ buflen = buf[1] + 2;
- if (eitevt->descriptor_tag != EIT_SHORT_EVENT_DESCRIPTOR)
+ if (evt->length_of_items > 0)
+ {
+ while (bufact - sizeof(eit_extended_event_t) < evt->length_of_items)
{
- // printf("Tag = '%c'\n", eitevt->descriptor_tag);
- continue;
+ strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]);
+ // could use value in tmp now to do something,
+ // haven't seen any items as of yet transmitted from satellite
+ bufact += (buf[bufact] + 1);
}
+ }
- if (((eit->service_id_hi << 8) | eit->service_id_lo) != uProgramNumber)
- {
- // printf("Wrong program %04x need %04x\n", (eit->service_id_hi << 8) | eit->service_id_lo, uProgramNumber);
- continue;
- }
-
- nReceivedEITs++;
+ strdvbcpy(tmp, &buf[bufact + 1], (int)buf[bufact]);
+ if (pEvent->AddExtendedDescription((char *)tmp))
+ {
+ pEvent->IncreaseExtendedDescriptorNumber();
+ return true;
+ }
- pevt = (eit_event *)0;
- if (eitloop->running_status == 4 | eitloop->running_status == 3)
- pevt = (eit_event *)&evtRunning;
- else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0)
- pevt = (eit_event *)&evtNext;
+ return false;
+}
+
+// --- cSIProcessor ----------------------------------------------------------
+
+#define MAX_FILTERS 20
+
+/** */
+cSIProcessor::cSIProcessor(const char *FileName)
+{
+ useTStime = false;
+ filters = NULL;
+ schedules = NULL;
+ if ((fsvbi = open(FileName, O_RDONLY)) >= 0)
+ {
+ schedules = new cSchedules;
+ filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER));
+ }
+ else
+ LOG_ERROR_STR(FileName);
+}
+
+cSIProcessor::~cSIProcessor()
+{
+ if (fsvbi >= 0)
+ {
+ Stop();
+ ShutDownFilters();
+ delete filters;
+ delete schedules;
+ close(fsvbi);
+ }
+}
+
+/** use the vbi device to parse all relevant SI
+information and let the classes corresponding
+to the tables write their information to the disk */
+void cSIProcessor::Action()
+{
+ if (fsvbi < 0) {
+ esyslog(LOG_ERR, "cSIProcessor::Action() called without open file - returning");
+ return;
+ }
+
+ dsyslog(LOG_INFO, "EIT processing thread started (pid=%d)", getpid());
+
+ unsigned char buf[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-)
+ unsigned int seclen;
+ unsigned int pid;
+ time_t lastCleanup = time(NULL);
+ struct pollfd pfd;
+
+ while(true)
+ {
+ time_t now = time(NULL);
+ struct tm *ptm = localtime(&now);
+ if (now - lastCleanup > 3600 && ptm->tm_hour == 5)
+ {
+ LOCK_THREAD;
- if (pevt)
+ isyslog(LOG_INFO, "Now cleaning up things");
+ schedules->Cleanup();
+ lastCleanup = now;
+ }
+
+ /* wait data become ready from the bitfilter */
+ pfd.fd = fsvbi;
+ pfd.events = POLLIN;
+ if(poll(&pfd, 1, 1000) != 0) /* timeout is 5 secs */
{
- unsigned char *p = (unsigned char *)&eitevt[1];
- strdvbcpy((unsigned char *)pevt->szTitle, p, eitevt->event_name_length);
- pevt->szSubTitle[0] = 0;
- strdvbcpy((unsigned char *)pevt->szSubTitle, &p[eitevt->event_name_length+1], (int)p[eitevt->event_name_length]);
- strcpy(pevt->szDate, mjd2string((eitloop->date_hi << 8) + eitloop->date_lo));
- int hr = eitloop->time_hour + (eitloop->time_hour_ten * 10);
- hr += 2;
- if (hr >=24)
+ // fprintf(stderr, "<data>\n");
+ /* read section */
+ read(fsvbi, buf, 8);
+ seclen = (buf[6] << 8) | buf[7];
+ pid = (buf[4] << 8) | buf[5];
+ read(fsvbi, buf, seclen);
+
+ //dsyslog(LOG_INFO, "Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen);
+
+ switch (pid)
{
- hr -= 24;
- // need to switch date one day ahead here
+ case 0x14:
+ if (buf[0] == 0x70)
+ {
+ if (useTStime)
+ {
+ cTDT ctdt((tdt_t *)buf);
+ ctdt.SetSystemTime();
+ }
+ }
+ /*XXX this comes pretty often:
+ else
+ dsyslog(LOG_INFO, "Time packet was not 0x70 but 0x%02x\n", (int)buf[0]);
+ XXX*/
+ break;
+
+ case 0x12:
+ if (buf[0] != 0x72)
+ {
+ LOCK_THREAD;
+
+ cEIT ceit(buf, seclen, schedules);
+ ceit.ProcessEIT();
+ }
+ else
+ dsyslog(LOG_INFO, "Received stuffing section in EIT\n");
+ break;
+
+ default:
+ break;
}
- sprintf(pevt->szTime, "%d:%c%c", hr,
- eitloop->time_minute_ten + '0',
- eitloop->time_minute + '0');
- pevt->bIsValid = true;
}
- }
-
- CloseFilter(handle);
+ else
+ {
+ LOCK_THREAD;
- return 1;
+ //XXX this comes pretty often
+ //isyslog(LOG_INFO, "Received timeout from poll, refreshing filters\n");
+ RefreshFilters();
+ }
+// WakeUp();
+ }
}
-/** */
-int cEIT::SetProgramNumber(unsigned short pnr)
+/** Add a filter with packet identifier pid and
+table identifer tid */
+bool cSIProcessor::AddFilter(u_char pid, u_char tid)
{
- if (pnr == 0)
- {
- evtRunning.bIsValid = false;
- evtNext.bIsValid = false;
- return -1;
- }
+ if (fsvbi < 0)
+ return false;
+
+ int section = ((int)tid << 8) | 0x00ff;
+
+ struct bitfilter filt = {
+ pid,
+ { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+ SECTION_CONTINUOS, 0,
+ FILTER_MEM,
+ {},
+ };
- if (pnr != uProgramNumber)
+ if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0)
+ return false;
+
+ for (int a = 0; a < MAX_FILTERS; a++)
{
- evtRunning.bIsValid = false;
- evtNext.bIsValid = false;
- uProgramNumber = pnr;
+ if (filters[a].inuse == false)
+ {
+ filters[a].pid = pid;
+ filters[a].tid = tid;
+ filters[a].handle = filt.handle;
+ filters[a].inuse = true;
+ // dsyslog(LOG_INFO, " Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid);
+ return true;
+ }
}
- return 1;
+
+ return false;
}
-/** retrieves the string for the running title */
-char * cEIT::GetRunningTitle()
-{
- if (evtRunning.bIsValid)
- return evtRunning.szTitle;
- else
- return "---";
-}
-/** Retrieves the string for the running subtitle */
-char * cEIT::GetRunningSubtitle()
-{
- if (evtRunning.bIsValid)
- return evtRunning.szSubTitle;
- else
- return "---";
-}
-/** Retrieves the string representing the
-date of the current event
- */
-char * cEIT::GetRunningDate()
+/** set whether local systems time should be
+set by the received TDT or TOT packets */
+bool cSIProcessor::SetUseTSTime(bool use)
{
- if (evtRunning.bIsValid)
- return evtRunning.szDate;
- else
- return "---";
-}
-/** Retrieves the string representing the
-time of the current event */
-char * cEIT::GetRunningTime()
-{
- if (evtRunning.bIsValid)
- return evtRunning.szTime;
- else
- return "---";
-}
-/** retrieves the string for the running title */
-char * cEIT::GetNextTitle()
-{
- if (evtNext.bIsValid)
- return evtNext.szTitle;
- else
- return "---";
+ useTStime = use;
+ return useTStime;
}
-/** Retrieves the string for the running subtitle */
-char * cEIT::GetNextSubtitle()
-{
- if (evtNext.bIsValid)
- return evtNext.szSubTitle;
- else
- return "---";
-}
-/** Retrieves the string representing the
-date of the current event
- */
-char * cEIT::GetNextDate()
-{
- if (evtNext.bIsValid)
- return evtNext.szDate;
- else
- return "---";
-}
-/** Retrieves the string representing the
-time of the current event */
-char * cEIT::GetNextTime()
+
+/** */
+bool cSIProcessor::ShutDownFilters()
{
- if (evtNext.bIsValid)
- return evtNext.szTime;
- else
- return "---";
+ if (fsvbi < 0)
+ return false;
+
+ bool ret = true;
+
+ for (int a = 0; a < MAX_FILTERS; a++)
+ {
+ if (filters[a].inuse == true)
+ {
+ if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &filters[a].handle) < 0)
+ ret = false;
+
+ // dsyslog(LOG_INFO, "Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid);
+
+ filters[a].inuse = false;
+ }
+ }
+
+ return ret;
}
-/** */
-bool cEIT::IsValid()
+/** */
+bool cSIProcessor::SetCurrentServiceID(unsigned short servid)
{
- GetEIT();
- return (evtRunning.bIsValid && evtNext.bIsValid);
+ LOCK_THREAD;
+ return schedules ? schedules->SetCurrentServiceID(servid) : false;
}
/** */
-int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max)
+bool cSIProcessor::RefreshFilters()
{
- int a;
- for (a = 0; a < max; a++)
+ if (fsvbi < 0)
+ return false;
+
+ bool ret = true;
+
+ ret = ShutDownFilters();
+
+ for (int a = 0; a < MAX_FILTERS; a++)
{
- if (*src == 0)
- break;
-
- if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff))
- *dst++ = *src++;
- else
- src++;
+ if (filters[a].inuse == false && filters[a].pid != 0 && filters[a].tid != 0)
+ {
+ if (!AddFilter(filters[a].pid, filters[a].tid))
+ ret = false;
+ }
}
- *dst = 0;
- return a;
+
+ return ret;
}
+