premiereepg.c
branchtrunk
changeset 10 967afc97e51d
parent 8 b5bd55cfd28f
child 12 5213337a6614
     1.1 --- a/premiereepg.c	Sat Dec 29 11:19:37 2007 +0100
     1.2 +++ b/premiereepg.c	Sat Dec 29 11:19:49 2007 +0100
     1.3 @@ -1,7 +1,7 @@
     1.4  /*
     1.5   * PremiereEpg plugin to VDR (C++)
     1.6   *
     1.7 - * (C) 2005 Stefan Huelswitt <s.huelswitt@gmx.de>
     1.8 + * (C) 2005-2006 Stefan Huelswitt <s.huelswitt@gmx.de>
     1.9   *
    1.10   * This code is base on the commandline tool premiereepg2vdr
    1.11   * (C) 2004-2005 by Axel Katzur software@katzur.de
    1.12 @@ -29,6 +29,7 @@
    1.13  #include <vdr/channels.h>
    1.14  #include <vdr/dvbdevice.h>
    1.15  #include <vdr/i18n.h>
    1.16 +#include <vdr/config.h>
    1.17  #include <libsi/section.h>
    1.18  #include <libsi/descriptor.h>
    1.19  
    1.20 @@ -49,9 +50,13 @@
    1.21  #define PMT_SCAN_TIMEOUT  10  // seconds
    1.22  #define PMT_SCAN_IDLE     300 // seconds
    1.23  
    1.24 -static const char *VERSION        = "0.0.5";
    1.25 +static const char *VERSION        = "0.0.6";
    1.26  static const char *DESCRIPTION    = "Parses extended Premiere EPG data";
    1.27  
    1.28 +#if APIVERSNUM < 10401
    1.29 +#error You need at least VDR API version 1.4.1 for this plugin
    1.30 +#endif
    1.31 +
    1.32  // --- cSetupPremiereEpg -------------------------------------------------------
    1.33  
    1.34  const char *optPats[] = {
    1.35 @@ -330,140 +335,27 @@
    1.36    SetupStore("RatingInfo",SetupPE.RatingInfo);
    1.37  }
    1.38  
    1.39 -// --- CIT ---------------------------------------------------------------------
    1.40 -
    1.41 -namespace SI {
    1.42 -
    1.43 -#define CIT_LEN 17
    1.44 -
    1.45 -struct cit {
    1.46 -   u_char table_id                               :8;
    1.47 -#if BYTE_ORDER == BIG_ENDIAN
    1.48 -   u_char section_syntax_indicator               :1;
    1.49 -   u_char                                        :3;
    1.50 -   u_char section_length_hi                      :4;
    1.51 -#else
    1.52 -   u_char section_length_hi                      :4;
    1.53 -   u_char                                        :3;
    1.54 -   u_char section_syntax_indicator               :1;
    1.55 -#endif
    1.56 -   u_char section_length_lo                      :8;
    1.57 -   u_char service_id_hi                          :8;
    1.58 -   u_char service_id_lo                          :8;
    1.59 -#if BYTE_ORDER == BIG_ENDIAN
    1.60 -   u_char                                        :2;
    1.61 -   u_char version_number                         :5;
    1.62 -   u_char current_next_indicator                 :1;
    1.63 -#else
    1.64 -   u_char current_next_indicator                 :1;
    1.65 -   u_char version_number                         :5;
    1.66 -   u_char                                        :2;
    1.67 -#endif
    1.68 -   u_char section_number                         :8;
    1.69 -   u_char last_section_number                    :8;
    1.70 -   u_char content_id_hi_hi                       :8;
    1.71 -   u_char content_id_hi_lo                       :8;
    1.72 -   u_char content_id_lo_hi                       :8;
    1.73 -   u_char content_id_lo_lo                       :8;
    1.74 -   u_char duration_h                             :8;
    1.75 -   u_char duration_m                             :8;
    1.76 -   u_char duration_s                             :8;
    1.77 -#if BYTE_ORDER == BIG_ENDIAN
    1.78 -   u_char                                        :4;
    1.79 -   u_char descriptors_loop_length_hi             :4;
    1.80 -#else
    1.81 -   u_char descriptors_loop_length_hi             :4;
    1.82 -   u_char                                        :4;
    1.83 -#endif
    1.84 -   u_char descriptors_loop_length_lo             :8;
    1.85 -};
    1.86 -
    1.87 -class CIT : public NumberedSection {
    1.88 -public:
    1.89 -   CIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
    1.90 -   CIT() {}
    1.91 -   int getContentId(void) const;
    1.92 -   time_t getDuration(void) const;
    1.93 -   DescriptorLoop eventDescriptors;
    1.94 -protected:
    1.95 -   virtual void Parse(void);
    1.96 -private:
    1.97 -   const cit *s;
    1.98 -};
    1.99 -
   1.100 -int CIT::getContentId(void) const {
   1.101 -   return (HILO(s->content_id_hi)<<16) | (HILO(s->content_id_lo));
   1.102 -}
   1.103 -
   1.104 -time_t CIT::getDuration(void) const {
   1.105 -   return DVBTime::getDuration(s->duration_h,s->duration_m,s->duration_s);
   1.106 -}
   1.107 -
   1.108 -void CIT::Parse(void) {
   1.109 -#if VDRVERSNUM >= 10343
   1.110 -   int offset=0;
   1.111 -#else
   1.112 -   unsigned int offset=0;
   1.113 -#endif
   1.114 -   data.setPointerAndOffset<const cit>(s, offset);
   1.115 -   eventDescriptors.setData(data+offset,HILO(s->descriptors_loop_length));
   1.116 -}
   1.117 -
   1.118 -} // end of namespace
   1.119 -
   1.120 -// --- cDescrF2 ----------------------------------------------------------------
   1.121 -
   1.122 -class cDescrF2 {
   1.123 -private:
   1.124 -  SI::Descriptor *d;
   1.125 -  SI::CharArray data;
   1.126 -  int idx, loop, nloop, index;
   1.127 -public:
   1.128 -  cDescrF2(SI::Descriptor *D);
   1.129 -  int TransportStreamId(void) { return data.TwoBytes(2); }
   1.130 -  int OrgNetworkId(void)      { return data.TwoBytes(4); }
   1.131 -  int ServiceId(void)         { return data.TwoBytes(6); }
   1.132 -  void Start(void);
   1.133 -  bool Next(void);
   1.134 -  time_t StartTime(void);
   1.135 -  int Index(void) { return index; }
   1.136 -  };
   1.137 -
   1.138 -cDescrF2::cDescrF2(SI::Descriptor *D)
   1.139 -{
   1.140 -  d=D;
   1.141 -  data=d->getData();
   1.142 -  Start();
   1.143 -}
   1.144 -
   1.145 -void cDescrF2::Start(void)
   1.146 -{
   1.147 -  idx=8; loop=0; nloop=-3; index=-1;
   1.148 -}
   1.149 -
   1.150 -bool cDescrF2::Next(void)
   1.151 -{
   1.152 -  loop+=3;
   1.153 -  if(loop>=nloop) {
   1.154 -    idx+=nloop+3;
   1.155 -    if(idx>=d->getLength()) return false;
   1.156 -    loop=0; nloop=data[idx+2];
   1.157 +// --- CRC16 -------------------------------------------------------------------
   1.158 +
   1.159 +#define POLY 0xA001 // CRC16
   1.160 +
   1.161 +unsigned int crc16(unsigned int crc, unsigned char const *p, int len)
   1.162 +{
   1.163 +  while(len--) {
   1.164 +    crc^=*p++;
   1.165 +    for(int i=0; i<8; i++)
   1.166 +      crc=(crc&1) ? (crc>>1)^POLY : (crc>>1);
   1.167      }
   1.168 - index++;
   1.169 - return true;
   1.170 -}
   1.171 -
   1.172 -time_t cDescrF2::StartTime(void)
   1.173 -{
   1.174 -  int off=idx+3+loop;
   1.175 -  return SI::DVBTime::getTime(data[idx+0],data[idx+1],data[off+0],data[off+1],data[off+2]);
   1.176 +  return crc&0xFFFF;
   1.177  }
   1.178  
   1.179  // --- cFilterPremiereEpg ------------------------------------------------------
   1.180  
   1.181 +#define STARTTIME_BIAS (20*60)
   1.182 +
   1.183  class cFilterPremiereEpg : public cFilter {
   1.184  private:
   1.185 -  int pmtpid, pmtidx, pmtnext;
   1.186 +  int pmtpid, pmtsid, pmtidx, pmtnext;
   1.187    //
   1.188    void NextPmt(void);
   1.189  protected:
   1.190 @@ -503,8 +395,8 @@
   1.191  
   1.192  void cFilterPremiereEpg::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
   1.193  {
   1.194 +  int now=time(0);
   1.195    if(Pid==0 && Tid==SI::TableIdPAT) {
   1.196 -    int now=time(0);
   1.197      if(!pmtnext || now>pmtnext) {
   1.198        if(pmtpid) NextPmt();
   1.199        if(!pmtpid) {
   1.200 @@ -516,6 +408,7 @@
   1.201              if(!assoc.isNITPid()) {
   1.202                if(idx++==pmtidx) {
   1.203                  pmtpid=assoc.getPid();
   1.204 +                pmtsid=assoc.getServiceId();
   1.205                  Add(pmtpid,0x02);
   1.206                  pmtnext=now+PMT_SCAN_TIMEOUT;
   1.207                  d(printf("PMT pid now 0x%04x (idx=%d)\n",pmtpid,pmtidx))
   1.208 @@ -534,7 +427,7 @@
   1.209      }
   1.210    else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) {
   1.211      SI::PMT pmt(Data,false);
   1.212 -    if(pmt.CheckCRCAndParse()) {
   1.213 +    if(pmt.CheckCRCAndParse() && pmt.getServiceId()==pmtsid) {
   1.214        SI::PMT::Stream stream;
   1.215        for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) {
   1.216          if(stream.getStreamType()==0x05) {
   1.217 @@ -575,20 +468,21 @@
   1.218        }
   1.219      }
   1.220    else if(Tid==0xA0 && Source()) {
   1.221 -    SI::CIT cit(Data,false);
   1.222 +    SI::PremiereCIT cit(Data,false);
   1.223      if(cit.CheckCRCAndParse()) {
   1.224        cSchedulesLock SchedulesLock(true,10);
   1.225        cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock);
   1.226        if(Schedules) {
   1.227          int nCount=0;
   1.228 -        time_t firstTime=0;
   1.229 -        SI::Descriptor *d;
   1.230 -        int LanguagePreferenceShort=-1;
   1.231 -        int LanguagePreferenceExt=-1;
   1.232 -        bool UseExtendedEventDescriptor=false;
   1.233          SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0;
   1.234          SI::ShortEventDescriptor *ShortEventDescriptor=0;
   1.235          char *order=0, *rating=0;
   1.236 +        {
   1.237 +        time_t firstTime=0;
   1.238 +        SI::Descriptor *d;
   1.239 +        bool UseExtendedEventDescriptor=false;
   1.240 +        int LanguagePreferenceShort=-1;
   1.241 +        int LanguagePreferenceExt=-1;
   1.242          for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
   1.243            switch(d->getDescriptorTag()) {
   1.244              case 0xF0: // order information
   1.245 @@ -623,15 +517,19 @@
   1.246                  if(p>0) rating=strdup(buff);
   1.247                  }
   1.248                break;
   1.249 -            case 0xF2: // transmisions
   1.250 +            case SI::PremiereContentTransmissionDescriptorTag:
   1.251                if(nCount>=0) {
   1.252 +                SI::PremiereContentTransmissionDescriptor *pct=(SI::PremiereContentTransmissionDescriptor *)d;
   1.253                  nCount++;
   1.254 -                cDescrF2 f2(d);
   1.255 -                if(f2.Next()) {
   1.256 -                  if(nCount==1) firstTime=f2.StartTime();
   1.257 -                  else {
   1.258 -                    time_t time=f2.StartTime();
   1.259 -                    if(firstTime<time-5*50 || firstTime>time+5*60)
   1.260 +                SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
   1.261 +                SI::Loop::Iterator it;
   1.262 +                if(pct->startDayLoop.getNext(sd,it)) {
   1.263 +                  SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
   1.264 +                  SI::Loop::Iterator it2;
   1.265 +                  if(sd.startTimeLoop.getNext(st,it2)) {
   1.266 +                    time_t StartTime=st.getStartTime(sd.getMJD());
   1.267 +                    if(nCount==1) firstTime=StartTime;
   1.268 +                    else if(firstTime<StartTime-5*50 || firstTime>StartTime+5*60)
   1.269                        nCount=-1;
   1.270                      }
   1.271                    }
   1.272 @@ -640,11 +538,7 @@
   1.273              case SI::ExtendedEventDescriptorTag:
   1.274                {
   1.275                SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d;
   1.276 -#if VDRVERSNUM < 10332
   1.277 -              if(I18nIsPreferredLanguage(Setup.EPGLanguages,I18nLanguageIndex(eed->languageCode), LanguagePreferenceExt) || !ExtendedEventDescriptors) {
   1.278 -#else
   1.279                if(I18nIsPreferredLanguage(Setup.EPGLanguages,eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
   1.280 -#endif
   1.281                   delete ExtendedEventDescriptors;
   1.282                   ExtendedEventDescriptors=new SI::ExtendedEventDescriptors;
   1.283                   UseExtendedEventDescriptor=true;
   1.284 @@ -660,11 +554,7 @@
   1.285              case SI::ShortEventDescriptorTag:
   1.286                {
   1.287                SI::ShortEventDescriptor *sed=(SI::ShortEventDescriptor *)d;
   1.288 -#if VDRVERSNUM < 10332
   1.289 -              if(I18nIsPreferredLanguage(Setup.EPGLanguages,I18nLanguageIndex(sed->languageCode), LanguagePreferenceShort) || !ShortEventDescriptor) {
   1.290 -#else
   1.291                if(I18nIsPreferredLanguage(Setup.EPGLanguages,sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
   1.292 -#endif
   1.293                   delete ShortEventDescriptor;
   1.294                   ShortEventDescriptor=sed;
   1.295                   d=NULL; // so that it is not deleted
   1.296 @@ -676,55 +566,64 @@
   1.297              }
   1.298            delete d;
   1.299            }
   1.300 -
   1.301 +        }
   1.302 +
   1.303 +        {
   1.304          bool Modified=false;
   1.305          int optCount=0;
   1.306 -        for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
   1.307 -          if(d->getDescriptorTag()==0xF2) {
   1.308 -            optCount++;
   1.309 -
   1.310 -            cDescrF2 f2(d);
   1.311 -            tChannelID channelID(Source(),f2.OrgNetworkId(),f2.TransportStreamId(),f2.ServiceId());
   1.312 -            cChannel *channel=Channels.GetByChannelID(channelID,true);
   1.313 -            if(!channel) continue;
   1.314 -
   1.315 -            cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID);
   1.316 -            if(!pSchedule) {
   1.317 -               pSchedule=new cSchedule(channelID);
   1.318 -               Schedules->Add(pSchedule);
   1.319 -               }
   1.320 -
   1.321 -            for(f2.Start(); f2.Next();) {
   1.322 -              u_int16_t EventId=(cit.getContentId()<<4) | f2.Index();
   1.323 -              time_t StartTime=f2.StartTime();
   1.324 -
   1.325 +        unsigned int crc[3];
   1.326 +        crc[0]=cit.getContentId();
   1.327 +        SI::PremiereContentTransmissionDescriptor *pct;
   1.328 +        for(SI::Loop::Iterator it; (pct=(SI::PremiereContentTransmissionDescriptor *)cit.eventDescriptors.getNext(it,SI::PremiereContentTransmissionDescriptorTag)); ) {
   1.329 +          tChannelID channelID(Source(),pct->getOriginalNetworkId(),pct->getTransportStreamId(),pct->getServiceId());
   1.330 +          cChannel *channel=Channels.GetByChannelID(channelID,true);
   1.331 +          if(!channel) continue;
   1.332 +
   1.333 +          cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID);
   1.334 +          if(!pSchedule) {
   1.335 +             pSchedule=new cSchedule(channelID);
   1.336 +             Schedules->Add(pSchedule);
   1.337 +             }
   1.338 +
   1.339 +          optCount++;
   1.340 +          SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
   1.341 +          int index=0;
   1.342 +          for(SI::Loop::Iterator it; pct->startDayLoop.getNext(sd,it); ) {
   1.343 +            int mjd=sd.getMJD();
   1.344 +            SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
   1.345 +            for(SI::Loop::Iterator it2; sd.startTimeLoop.getNext(st,it2); ) {
   1.346 +              time_t StartTime=st.getStartTime(mjd);
   1.347 +              time_t EndTime=StartTime+cit.getDuration();
   1.348 +              int runningStatus=(StartTime<now && now<EndTime) ? SI::RunningStatusRunning : ((StartTime-30<now && now<StartTime) ? SI::RunningStatusStartsInAFewSeconds : SI::RunningStatusNotRunning);
   1.349                bool isOpt=false;
   1.350 -              if(f2.Index()==0 && nCount>1) isOpt=true;
   1.351 -
   1.352 -              d2(printf("ch=%s id=%04x/%08x %d opt=%d/%d st=%s ",*channelID.ToString(),EventId,cit.getContentId(),f2.Index(),isOpt,optCount,stripspace(ctime(&StartTime))))
   1.353 -              if(StartTime+cit.getDuration()+Setup.EPGLinger*60<time(0)) {
   1.354 +              if(index++==0 && nCount>1) isOpt=true;
   1.355 +              crc[1]=isOpt ? optCount : 0;
   1.356 +              crc[2]=StartTime / STARTTIME_BIAS;
   1.357 +              tEventID EventId=((('P'<<8)|'W')<<16) | crc16(0,(unsigned char *)crc,sizeof(crc));
   1.358 +
   1.359 +              d2(printf("%s R%d %04x/%.4x %d %d/%d %s +%d ",*channelID.ToString(),runningStatus,EventId&0xFFFF,cit.getContentId(),index,isOpt,optCount,stripspace(ctime(&StartTime)),(int)cit.getDuration()/60))
   1.360 +              if(EndTime+Setup.EPGLinger*60<now) {
   1.361                  d2(printf("(old)\n"))
   1.362                  continue;
   1.363                  }
   1.364  
   1.365                bool newEvent=false;
   1.366 -              cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,StartTime);
   1.367 +              cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,-1);
   1.368                if(!pEvent) {
   1.369 -                 d2(printf("(new)\n"))
   1.370 -#if VDRVERSNUM >= 10325
   1.371 -                 pEvent=new cEvent(EventId);
   1.372 -#else
   1.373 -                 pEvent=new cEvent(channelID,EventId);
   1.374 -#endif
   1.375 -                 if(!pEvent) continue;
   1.376 -                 newEvent=true;
   1.377 -                 }
   1.378 +                d2(printf("(new)\n"))
   1.379 +                pEvent=new cEvent(EventId);
   1.380 +                if(!pEvent) continue;
   1.381 +                newEvent=true;
   1.382 +                }
   1.383                else {
   1.384 -                 d2(printf("(upd)\n"))
   1.385 -                 pEvent->SetSeen();
   1.386 -                 if(pEvent->TableID()==0x00) continue;
   1.387 -                 if(Tid==pEvent->TableID() && pEvent->Version()==cit.getVersionNumber()) continue;
   1.388 -                 }
   1.389 +                d2(printf("(upd)\n"))
   1.390 +                pEvent->SetSeen();
   1.391 +                if(pEvent->TableID()==0x00 || pEvent->Version()==cit.getVersionNumber()) {
   1.392 +                  if(pEvent->RunningStatus()!=runningStatus)
   1.393 +                    pSchedule->SetRunningStatus(pEvent,runningStatus,channel);
   1.394 +                  continue;
   1.395 +                  }
   1.396 +                }
   1.397                pEvent->SetEventID(EventId);
   1.398                pEvent->SetTableID(Tid);
   1.399                pEvent->SetVersion(cit.getVersionNumber());
   1.400 @@ -741,6 +640,7 @@
   1.401                    }
   1.402                  else
   1.403                    pEvent->SetTitle(buffer);
   1.404 +                d2(printf("title: %s\n",pEvent->Title()))
   1.405                  pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer)));
   1.406                  }
   1.407                if(ExtendedEventDescriptors) {
   1.408 @@ -760,19 +660,21 @@
   1.409                  }
   1.410  
   1.411                if(newEvent) pSchedule->AddEvent(pEvent);
   1.412 -#if VDRVERSNUM >= 10318
   1.413                pEvent->SetComponents(NULL);
   1.414 -#endif
   1.415                pEvent->FixEpgBugs();
   1.416 +              if(pEvent->RunningStatus()!=runningStatus)
   1.417 +                pSchedule->SetRunningStatus(pEvent,runningStatus,channel);
   1.418 +              pSchedule->DropOutdated(StartTime,EndTime,Tid,cit.getVersionNumber());
   1.419                Modified=true;
   1.420                }
   1.421 -            if(Modified) {
   1.422 -              pSchedule->Sort();
   1.423 -              Schedules->SetModified(pSchedule);
   1.424 -              }
   1.425              }
   1.426 -          delete d;
   1.427 +          if(Modified) {
   1.428 +            pSchedule->Sort();
   1.429 +            Schedules->SetModified(pSchedule);
   1.430 +            }
   1.431 +          delete pct;
   1.432            }
   1.433 +        }
   1.434          delete ExtendedEventDescriptors;
   1.435          delete ShortEventDescriptor;
   1.436          free(order);