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