premiereepg.c
author nathan
Sat, 29 Dec 2007 11:17:32 +0100
branchtrunk
changeset 0 a75b9f441157
child 2 3562cacb3b0b
permissions -rw-r--r--
release 0.0.1
nathan@0
     1
/*
nathan@0
     2
 * PremiereEpg plugin to VDR (C++)
nathan@0
     3
 *
nathan@0
     4
 * (C) 2005 Stefan Huelswitt <s.huelswitt@gmx.de>
nathan@0
     5
 *
nathan@0
     6
 * This code is base on the commandline tool premiereepg2vdr
nathan@0
     7
 * (C) 2004-2005 by Axel Katzur software@katzur.de
nathan@0
     8
 * but has been rewritten from scratch
nathan@0
     9
 *
nathan@0
    10
 * This code is free software; you can redistribute it and/or
nathan@0
    11
 * modify it under the terms of the GNU General Public License
nathan@0
    12
 * as published by the Free Software Foundation; either version 2
nathan@0
    13
 * of the License, or (at your option) any later version.
nathan@0
    14
 *
nathan@0
    15
 * This code is distributed in the hope that it will be useful,
nathan@0
    16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nathan@0
    17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nathan@0
    18
 * GNU General Public License for more details.
nathan@0
    19
 *
nathan@0
    20
 * You should have received a copy of the GNU General Public License
nathan@0
    21
 * along with this program; if not, write to the Free Software
nathan@0
    22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
nathan@0
    23
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
nathan@0
    24
 */
nathan@0
    25
nathan@0
    26
#include <vdr/plugin.h>
nathan@0
    27
#include <vdr/filter.h>
nathan@0
    28
#include <vdr/epg.h>
nathan@0
    29
#include <vdr/channels.h>
nathan@0
    30
#include <vdr/dvbdevice.h>
nathan@0
    31
#include <libsi/section.h>
nathan@0
    32
#include <libsi/descriptor.h>
nathan@0
    33
nathan@0
    34
//#define DEBUG
nathan@0
    35
//#define DEBUG2
nathan@0
    36
nathan@0
    37
#ifdef DEBUG
nathan@0
    38
#define d(x) { (x); }
nathan@0
    39
#else
nathan@0
    40
#define d(x) ; 
nathan@0
    41
#endif
nathan@0
    42
#ifdef DEBUG2
nathan@0
    43
#define d2(x) { (x); }
nathan@0
    44
#else
nathan@0
    45
#define d2(x) ; 
nathan@0
    46
#endif
nathan@0
    47
nathan@0
    48
#define PMT_SCAN_TIMEOUT  10  // seconds
nathan@0
    49
#define PMT_SCAN_IDLE     300 // seconds
nathan@0
    50
nathan@0
    51
static const char *VERSION        = "0.0.1";
nathan@0
    52
static const char *DESCRIPTION    = "Parse extended Premiere EPG data";
nathan@0
    53
nathan@0
    54
// --- CIT ---------------------------------------------------------------------
nathan@0
    55
nathan@0
    56
namespace SI {
nathan@0
    57
nathan@0
    58
#define CIT_LEN 17
nathan@0
    59
nathan@0
    60
struct cit {
nathan@0
    61
   u_char table_id                               :8;
nathan@0
    62
#if BYTE_ORDER == BIG_ENDIAN
nathan@0
    63
   u_char section_syntax_indicator               :1;
nathan@0
    64
   u_char                                        :3;
nathan@0
    65
   u_char section_length_hi                      :4;
nathan@0
    66
#else
nathan@0
    67
   u_char section_length_hi                      :4;
nathan@0
    68
   u_char                                        :3;
nathan@0
    69
   u_char section_syntax_indicator               :1;
nathan@0
    70
#endif
nathan@0
    71
   u_char section_length_lo                      :8;
nathan@0
    72
   u_char service_id_hi                          :8;
nathan@0
    73
   u_char service_id_lo                          :8;
nathan@0
    74
#if BYTE_ORDER == BIG_ENDIAN
nathan@0
    75
   u_char                                        :2;
nathan@0
    76
   u_char version_number                         :5;
nathan@0
    77
   u_char current_next_indicator                 :1;
nathan@0
    78
#else
nathan@0
    79
   u_char current_next_indicator                 :1;
nathan@0
    80
   u_char version_number                         :5;
nathan@0
    81
   u_char                                        :2;
nathan@0
    82
#endif
nathan@0
    83
   u_char section_number                         :8;
nathan@0
    84
   u_char last_section_number                    :8;
nathan@0
    85
   u_char content_id_hi_hi                       :8;
nathan@0
    86
   u_char content_id_hi_lo                       :8;
nathan@0
    87
   u_char content_id_lo_hi                       :8;
nathan@0
    88
   u_char content_id_lo_lo                       :8;
nathan@0
    89
   u_char duration_h                             :8;
nathan@0
    90
   u_char duration_m                             :8;
nathan@0
    91
   u_char duration_s                             :8;
nathan@0
    92
#if BYTE_ORDER == BIG_ENDIAN
nathan@0
    93
   u_char reserved                               :4;
nathan@0
    94
   u_char descriptors_loop_length_hi             :4;
nathan@0
    95
#else
nathan@0
    96
   u_char descriptors_loop_length_hi             :4;
nathan@0
    97
   u_char reserved                               :4;
nathan@0
    98
#endif
nathan@0
    99
   u_char descriptors_loop_length_lo             :8;
nathan@0
   100
};
nathan@0
   101
nathan@0
   102
class CIT : public NumberedSection {
nathan@0
   103
public:
nathan@0
   104
   CIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {}
nathan@0
   105
   CIT() {}
nathan@0
   106
   int getContentId(void) const;
nathan@0
   107
   time_t getDuration(void) const;
nathan@0
   108
   DescriptorLoop eventDescriptors;
nathan@0
   109
protected:
nathan@0
   110
   virtual void Parse(void);
nathan@0
   111
private:
nathan@0
   112
   const cit *s;
nathan@0
   113
};
nathan@0
   114
nathan@0
   115
int CIT::getContentId(void) const {
nathan@0
   116
   return (HILO(s->content_id_hi)<<16) | (HILO(s->content_id_lo));
nathan@0
   117
}
nathan@0
   118
nathan@0
   119
time_t CIT::getDuration(void) const {
nathan@0
   120
   return DVBTime::getDuration(s->duration_h,s->duration_m,s->duration_s);
nathan@0
   121
}
nathan@0
   122
nathan@0
   123
void CIT::Parse(void) {
nathan@0
   124
   unsigned int offset=0;
nathan@0
   125
   data.setPointerAndOffset<const cit>(s, offset);
nathan@0
   126
   eventDescriptors.setData(data+offset,HILO(s->descriptors_loop_length));
nathan@0
   127
}
nathan@0
   128
nathan@0
   129
} // end of namespace
nathan@0
   130
nathan@0
   131
// --- cDescrF2 ----------------------------------------------------------------
nathan@0
   132
nathan@0
   133
class cDescrF2 {
nathan@0
   134
private:
nathan@0
   135
  SI::Descriptor *d;
nathan@0
   136
  SI::CharArray data;
nathan@0
   137
  int idx, loop, nloop, index;
nathan@0
   138
public:
nathan@0
   139
  cDescrF2(SI::Descriptor *D);
nathan@0
   140
  int TransportStreamId(void) { return data.TwoBytes(2); }
nathan@0
   141
  int OrgNetworkId(void)      { return data.TwoBytes(4); }
nathan@0
   142
  int ServiceId(void)         { return data.TwoBytes(6); }
nathan@0
   143
  void Start(void);
nathan@0
   144
  bool Next(void);
nathan@0
   145
  time_t StartTime(void);
nathan@0
   146
  int Index(void) { return index; }
nathan@0
   147
  };
nathan@0
   148
nathan@0
   149
cDescrF2::cDescrF2(SI::Descriptor *D)
nathan@0
   150
{
nathan@0
   151
  d=D;
nathan@0
   152
  data=d->getData();
nathan@0
   153
  Start();
nathan@0
   154
}
nathan@0
   155
nathan@0
   156
void cDescrF2::Start(void)
nathan@0
   157
{
nathan@0
   158
  idx=8; loop=0; nloop=-3; index=-1;
nathan@0
   159
}
nathan@0
   160
nathan@0
   161
bool cDescrF2::Next(void)
nathan@0
   162
{
nathan@0
   163
  loop+=3;
nathan@0
   164
  if(loop>=nloop) {
nathan@0
   165
    idx+=nloop+3;
nathan@0
   166
    if(idx>=d->getLength()) return false;
nathan@0
   167
    loop=0; nloop=data[idx+2];
nathan@0
   168
    }
nathan@0
   169
 index++;
nathan@0
   170
 return true;
nathan@0
   171
}
nathan@0
   172
nathan@0
   173
time_t cDescrF2::StartTime(void)
nathan@0
   174
{
nathan@0
   175
  int off=idx+3+loop;
nathan@0
   176
  return SI::DVBTime::getTime(data[idx+0],data[idx+1],data[off+0],data[off+1],data[off+2]);
nathan@0
   177
}
nathan@0
   178
nathan@0
   179
// --- cFilterPremiereEpg ------------------------------------------------------
nathan@0
   180
nathan@0
   181
class cFilterPremiereEpg : public cFilter {
nathan@0
   182
private:
nathan@0
   183
  int pmtpid, pmtidx, pmtnext;
nathan@0
   184
  //
nathan@0
   185
  void NextPmt(void);
nathan@0
   186
protected:
nathan@0
   187
  virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
nathan@0
   188
public:
nathan@0
   189
  cFilterPremiereEpg(void);
nathan@0
   190
  virtual void SetStatus(bool On);
nathan@0
   191
  void Trigger(void);
nathan@0
   192
  };
nathan@0
   193
nathan@0
   194
cFilterPremiereEpg::cFilterPremiereEpg(void)
nathan@0
   195
{
nathan@0
   196
  Trigger();
nathan@0
   197
  Set(0x00,0x00);
nathan@0
   198
}
nathan@0
   199
nathan@0
   200
void cFilterPremiereEpg::Trigger(void)
nathan@0
   201
{
nathan@0
   202
  d(printf("trigger\n"))
nathan@0
   203
  pmtpid=0; pmtidx=0; pmtnext=0;
nathan@0
   204
}
nathan@0
   205
nathan@0
   206
void cFilterPremiereEpg::SetStatus(bool On)
nathan@0
   207
{
nathan@0
   208
  d(printf("setstatus %d\n",On))
nathan@0
   209
  cFilter::SetStatus(On);
nathan@0
   210
  Trigger();
nathan@0
   211
}
nathan@0
   212
nathan@0
   213
void cFilterPremiereEpg::NextPmt(void)
nathan@0
   214
{
nathan@0
   215
  Del(pmtpid,0x02);
nathan@0
   216
  pmtpid=0;
nathan@0
   217
  pmtidx++;
nathan@0
   218
  d(printf("PMT next\n"))
nathan@0
   219
}
nathan@0
   220
nathan@0
   221
void cFilterPremiereEpg::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
nathan@0
   222
{
nathan@0
   223
  if(Pid==0 && Tid==SI::TableIdPAT) {
nathan@0
   224
    int now=time(0);
nathan@0
   225
    if(!pmtnext || now>pmtnext) {
nathan@0
   226
      if(pmtpid) NextPmt();
nathan@0
   227
      if(!pmtpid) {
nathan@0
   228
        SI::PAT pat(Data,false);
nathan@0
   229
        if(pat.CheckCRCAndParse()) {
nathan@0
   230
          SI::PAT::Association assoc;
nathan@0
   231
          int idx=0;
nathan@0
   232
          for(SI::Loop::Iterator it; pat.associationLoop.getNext(assoc,it);) {
nathan@0
   233
            if(!assoc.isNITPid()) {
nathan@0
   234
              if(idx++==pmtidx) {
nathan@0
   235
                pmtpid=assoc.getPid();
nathan@0
   236
                Add(pmtpid,0x02);
nathan@0
   237
                pmtnext=now+PMT_SCAN_TIMEOUT;
nathan@0
   238
                d(printf("PMT pid now 0x%04x (idx=%d)\n",pmtpid,pmtidx))
nathan@0
   239
                break;
nathan@0
   240
                }
nathan@0
   241
              }
nathan@0
   242
            }
nathan@0
   243
          if(!pmtpid) {
nathan@0
   244
            pmtidx=0;
nathan@0
   245
            pmtnext=now+PMT_SCAN_IDLE;
nathan@0
   246
            d(printf("PMT scan idle\n"))
nathan@0
   247
            }
nathan@0
   248
          }
nathan@0
   249
        }
nathan@0
   250
      }
nathan@0
   251
    }
nathan@0
   252
  else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) {
nathan@0
   253
    SI::PMT pmt(Data,false);
nathan@0
   254
    if(pmt.CheckCRCAndParse()) {
nathan@0
   255
      SI::PMT::Stream stream;
nathan@0
   256
      for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) {
nathan@0
   257
        if(stream.getStreamType()==0x05) {
nathan@0
   258
          SI::CharArray data=stream.getData();
nathan@0
   259
          if((data[1]&0xE0)==0xE0 && (data[3]&0xF0)==0xF0) {
nathan@0
   260
            bool prvData=false, usrData=false;
nathan@0
   261
            SI::Descriptor *d;
nathan@0
   262
            for(SI::Loop::Iterator it; (d=stream.streamDescriptors.getNext(it)); ) {
nathan@0
   263
              switch(d->getDescriptorTag()) {
nathan@0
   264
                case SI::PrivateDataSpecifierDescriptorTag:
nathan@0
   265
                  d(printf("prv: %d %08x\n",d->getLength(),d->getData().FourBytes(2)))
nathan@0
   266
                  if(d->getLength()==6 && d->getData().FourBytes(2)==0x000000be)
nathan@0
   267
                    prvData=true;
nathan@0
   268
                  break;
nathan@0
   269
                case 0x90:
nathan@0
   270
                  d(printf("usr: %d %08x\n",d->getLength(),d->getData().FourBytes(2)))
nathan@0
   271
                  if(d->getLength()==6 && d->getData().FourBytes(2)==0x0000ffff)
nathan@0
   272
                    usrData=true;
nathan@0
   273
                  break;
nathan@0
   274
                default:
nathan@0
   275
                  break;
nathan@0
   276
                }
nathan@0
   277
              delete d;
nathan@0
   278
              }
nathan@0
   279
            if(prvData && usrData) {
nathan@0
   280
              int pid=stream.getPid();
nathan@0
   281
              d(printf("found citpid 0x%04x",pid))
nathan@0
   282
              if(!Matches(pid,0xA0)) {
nathan@0
   283
                Add(pid,0xA0);
nathan@0
   284
                d(printf(" (added)"))
nathan@0
   285
                }
nathan@0
   286
              d(printf("\n"))
nathan@0
   287
              }
nathan@0
   288
            }
nathan@0
   289
          }
nathan@0
   290
        }
nathan@0
   291
      NextPmt(); pmtnext=0;
nathan@0
   292
      }
nathan@0
   293
    }
nathan@0
   294
  else if(Tid==0xA0 && Source()) {
nathan@0
   295
    SI::CIT cit(Data,false);
nathan@0
   296
    if(cit.CheckCRCAndParse()) {
nathan@0
   297
      cSchedulesLock SchedulesLock(true,10);
nathan@0
   298
      cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock);
nathan@0
   299
      if(Schedules) {
nathan@0
   300
        int nCount=0;
nathan@0
   301
        time_t firstTime=0;
nathan@0
   302
        SI::Descriptor *d;
nathan@0
   303
        int LanguagePreferenceShort=-1;
nathan@0
   304
        int LanguagePreferenceExt=-1;
nathan@0
   305
        bool UseExtendedEventDescriptor=false;
nathan@0
   306
        SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0;
nathan@0
   307
        SI::ShortEventDescriptor *ShortEventDescriptor=0;
nathan@0
   308
        for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
nathan@0
   309
          switch(d->getDescriptorTag()) {
nathan@0
   310
            case 0xF2:
nathan@0
   311
              if(nCount>=0) {
nathan@0
   312
                nCount++;
nathan@0
   313
                cDescrF2 f2(d);
nathan@0
   314
                if(f2.Next()) {
nathan@0
   315
                  if(nCount==1) firstTime=f2.StartTime();
nathan@0
   316
                  else {
nathan@0
   317
                    time_t time=f2.StartTime();
nathan@0
   318
                    if(firstTime<time-5*50 || firstTime>time+5*60)
nathan@0
   319
                      nCount=-1;
nathan@0
   320
                    }
nathan@0
   321
                  }
nathan@0
   322
                }
nathan@0
   323
              break;
nathan@0
   324
            case SI::ExtendedEventDescriptorTag:
nathan@0
   325
              {
nathan@0
   326
              SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d;
nathan@0
   327
              if(I18nIsPreferredLanguage(Setup.EPGLanguages,I18nLanguageIndex(eed->languageCode), LanguagePreferenceExt) || !ExtendedEventDescriptors) {
nathan@0
   328
                 delete ExtendedEventDescriptors;
nathan@0
   329
                 ExtendedEventDescriptors=new SI::ExtendedEventDescriptors;
nathan@0
   330
                 UseExtendedEventDescriptor=true;
nathan@0
   331
                 }
nathan@0
   332
              if(UseExtendedEventDescriptor) {
nathan@0
   333
                 ExtendedEventDescriptors->Add(eed);
nathan@0
   334
                 d=NULL; // so that it is not deleted
nathan@0
   335
                 }
nathan@0
   336
              if(eed->getDescriptorNumber()==eed->getLastDescriptorNumber())
nathan@0
   337
                 UseExtendedEventDescriptor=false;
nathan@0
   338
              }
nathan@0
   339
              break;
nathan@0
   340
            case SI::ShortEventDescriptorTag:
nathan@0
   341
              {
nathan@0
   342
              SI::ShortEventDescriptor *sed=(SI::ShortEventDescriptor *)d;
nathan@0
   343
              if(I18nIsPreferredLanguage(Setup.EPGLanguages,I18nLanguageIndex(sed->languageCode), LanguagePreferenceShort) || !ShortEventDescriptor) {
nathan@0
   344
                 delete ShortEventDescriptor;
nathan@0
   345
                 ShortEventDescriptor=sed;
nathan@0
   346
                 d=NULL; // so that it is not deleted
nathan@0
   347
                 }
nathan@0
   348
              }
nathan@0
   349
              break;
nathan@0
   350
            default:
nathan@0
   351
              break;
nathan@0
   352
            }
nathan@0
   353
          delete d;
nathan@0
   354
          }
nathan@0
   355
nathan@0
   356
        bool Modified=false;
nathan@0
   357
        int optCount=0;
nathan@0
   358
        for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
nathan@0
   359
          if(d->getDescriptorTag()==0xF2) {
nathan@0
   360
            optCount++;
nathan@0
   361
nathan@0
   362
            cDescrF2 f2(d);
nathan@0
   363
            tChannelID channelID(Source(),f2.OrgNetworkId(),f2.TransportStreamId(),f2.ServiceId());
nathan@0
   364
            cChannel *channel=Channels.GetByChannelID(channelID,true);
nathan@0
   365
            if(!channel) continue;
nathan@0
   366
nathan@0
   367
            cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID);
nathan@0
   368
            if(!pSchedule) {
nathan@0
   369
               pSchedule=new cSchedule(channelID);
nathan@0
   370
               Schedules->Add(pSchedule);
nathan@0
   371
               }
nathan@0
   372
nathan@0
   373
            for(f2.Start(); f2.Next();) {
nathan@0
   374
              u_int16_t EventId=(cit.getContentId()<<4) | f2.Index();
nathan@0
   375
              time_t StartTime=f2.StartTime();
nathan@0
   376
nathan@0
   377
              bool isOpt=false;
nathan@0
   378
              if(f2.Index()==0 && nCount>1) isOpt=true;
nathan@0
   379
nathan@0
   380
              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))))
nathan@0
   381
              if(StartTime+cit.getDuration()+Setup.EPGLinger*60<time(0)) {
nathan@0
   382
                d2(printf("(old)\n"))
nathan@0
   383
                continue;
nathan@0
   384
                }
nathan@0
   385
nathan@0
   386
              cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,StartTime);
nathan@0
   387
              if(!pEvent) {
nathan@0
   388
                 d2(printf("(new)\n"))
nathan@0
   389
                 pEvent=pSchedule->AddEvent(new cEvent(channelID,EventId));
nathan@0
   390
                 if(!pEvent) continue;
nathan@0
   391
                 }
nathan@0
   392
              else {
nathan@0
   393
                 d2(printf("(upd)\n"))
nathan@0
   394
                 pEvent->SetSeen();
nathan@0
   395
                 if(pEvent->TableID()==0x00) continue;
nathan@0
   396
                 if(Tid==pEvent->TableID() && pEvent->Version()==cit.getVersionNumber()) continue;
nathan@0
   397
                 }
nathan@0
   398
              pEvent->SetEventID(EventId);
nathan@0
   399
              pEvent->SetTableID(Tid);
nathan@0
   400
              pEvent->SetVersion(cit.getVersionNumber());
nathan@0
   401
              pEvent->SetStartTime(StartTime);
nathan@0
   402
              pEvent->SetDuration(cit.getDuration());
nathan@0
   403
nathan@0
   404
              if(ShortEventDescriptor) {
nathan@0
   405
                char buffer[256+32];
nathan@0
   406
                ShortEventDescriptor->name.getText(buffer,sizeof(buffer)-32);
nathan@0
   407
                if(isOpt) {
nathan@0
   408
                  char o[32];
nathan@0
   409
                  snprintf(o,sizeof(o)," (Option %d)",optCount);
nathan@0
   410
                  strcat(buffer,o);
nathan@0
   411
                  }
nathan@0
   412
                pEvent->SetTitle(buffer);
nathan@0
   413
                pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer)));
nathan@0
   414
                }
nathan@0
   415
              if(ExtendedEventDescriptors) {
nathan@0
   416
                char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ")+1];
nathan@0
   417
                pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer,sizeof(buffer),": "));
nathan@0
   418
                }
nathan@0
   419
nathan@0
   420
              pEvent->SetComponents(NULL);
nathan@0
   421
              pEvent->FixEpgBugs();
nathan@0
   422
              Modified=true;
nathan@0
   423
              }
nathan@0
   424
            if(Modified) {
nathan@0
   425
              pSchedule->Sort();
nathan@0
   426
              Schedules->SetModified(pSchedule);
nathan@0
   427
              }
nathan@0
   428
            }
nathan@0
   429
          delete d;
nathan@0
   430
          }
nathan@0
   431
        delete ExtendedEventDescriptors;
nathan@0
   432
        delete ShortEventDescriptor;
nathan@0
   433
        }
nathan@0
   434
      }
nathan@0
   435
    }
nathan@0
   436
}
nathan@0
   437
nathan@0
   438
// --- cPluginPremiereEpg ------------------------------------------------------
nathan@0
   439
nathan@0
   440
class cPluginPremiereEpg : public cPlugin {
nathan@0
   441
private:
nathan@0
   442
  struct {
nathan@0
   443
    cFilterPremiereEpg *filter;
nathan@0
   444
    cDevice *device;
nathan@0
   445
    } epg[MAXDVBDEVICES];
nathan@0
   446
public:
nathan@0
   447
  cPluginPremiereEpg(void);
nathan@0
   448
  virtual const char *Version(void) { return VERSION; }
nathan@0
   449
  virtual const char *Description(void) { return DESCRIPTION; }
nathan@0
   450
  virtual bool Start(void);
nathan@0
   451
  virtual void Stop(void);
nathan@0
   452
  };
nathan@0
   453
nathan@0
   454
cPluginPremiereEpg::cPluginPremiereEpg(void)
nathan@0
   455
{
nathan@0
   456
  memset(epg,0,sizeof(epg));
nathan@0
   457
}
nathan@0
   458
nathan@0
   459
bool cPluginPremiereEpg::Start(void)
nathan@0
   460
{
nathan@0
   461
  for(int i=0; i<MAXDVBDEVICES; i++) {
nathan@0
   462
    cDevice *dev=cDevice::GetDevice(i);
nathan@0
   463
    if(dev) {
nathan@0
   464
      epg[i].device=dev;
nathan@0
   465
      dev->AttachFilter(epg[i].filter=new cFilterPremiereEpg);
nathan@0
   466
      isyslog("Attached premiere EPG filter to device %d",i);
nathan@0
   467
      }
nathan@0
   468
    }
nathan@0
   469
  return true;
nathan@0
   470
}
nathan@0
   471
nathan@0
   472
void cPluginPremiereEpg::Stop(void)
nathan@0
   473
{
nathan@0
   474
  for(int i=0; i<MAXDVBDEVICES; i++) {
nathan@0
   475
    cDevice *dev=epg[i].device;
nathan@0
   476
    if(dev) dev->Detach(epg[i].filter);
nathan@0
   477
    delete epg[i].filter;
nathan@0
   478
    epg[i].device=0;
nathan@0
   479
    epg[i].filter=0;
nathan@0
   480
    }
nathan@0
   481
}
nathan@0
   482
nathan@0
   483
VDRPLUGINCREATOR(cPluginPremiereEpg); // Don't touch this!