vdr  1.7.27
sdt.c
Go to the documentation of this file.
00001 /*
00002  * sdt.c: SDT section filter
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: sdt.c 2.5 2010/05/16 14:23:21 kls Exp $
00008  */
00009 
00010 #include "sdt.h"
00011 #include "channels.h"
00012 #include "config.h"
00013 #include "libsi/section.h"
00014 #include "libsi/descriptor.h"
00015 
00016 // --- cSdtFilter ------------------------------------------------------------
00017 
00018 cSdtFilter::cSdtFilter(cPatFilter *PatFilter)
00019 {
00020   patFilter = PatFilter;
00021   Set(0x11, 0x42);  // SDT
00022 }
00023 
00024 void cSdtFilter::SetStatus(bool On)
00025 {
00026   cFilter::SetStatus(On);
00027   sectionSyncer.Reset();
00028 }
00029 
00030 void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
00031 {
00032   if (!(Source() && Transponder()))
00033      return;
00034   SI::SDT sdt(Data, false);
00035   if (!sdt.CheckCRCAndParse())
00036      return;
00037   if (!sectionSyncer.Sync(sdt.getVersionNumber(), sdt.getSectionNumber(), sdt.getLastSectionNumber()))
00038      return;
00039   if (!Channels.Lock(true, 10))
00040      return;
00041   SI::SDT::Service SiSdtService;
00042   for (SI::Loop::Iterator it; sdt.serviceLoop.getNext(SiSdtService, it); ) {
00043       cChannel *channel = Channels.GetByChannelID(tChannelID(Source(), sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId()));
00044       if (!channel)
00045          channel = Channels.GetByChannelID(tChannelID(Source(), 0, Transponder(), SiSdtService.getServiceId()));
00046 
00047       cLinkChannels *LinkChannels = NULL;
00048       SI::Descriptor *d;
00049       for (SI::Loop::Iterator it2; (d = SiSdtService.serviceDescriptors.getNext(it2)); ) {
00050           switch (d->getDescriptorTag()) {
00051             case SI::ServiceDescriptorTag: {
00052                  SI::ServiceDescriptor *sd = (SI::ServiceDescriptor *)d;
00053                  switch (sd->getServiceType()) {
00054                    case 0x01: // digital television service
00055                    case 0x02: // digital radio sound service
00056                    case 0x04: // NVOD reference service
00057                    case 0x05: // NVOD time-shifted service
00058                    case 0x16: // digital SD television service
00059                    case 0x19: // digital HD television service
00060                         {
00061                         char NameBuf[Utf8BufSize(1024)];
00062                         char ShortNameBuf[Utf8BufSize(1024)];
00063                         char ProviderNameBuf[Utf8BufSize(1024)];
00064                         sd->serviceName.getText(NameBuf, ShortNameBuf, sizeof(NameBuf), sizeof(ShortNameBuf));
00065                         char *pn = compactspace(NameBuf);
00066                         char *ps = compactspace(ShortNameBuf);
00067                         if (!*ps && cSource::IsCable(Source())) {
00068                            // Some cable providers don't mark short channel names according to the
00069                            // standard, but rather go their own way and use "name>short name":
00070                            char *p = strchr(pn, '>'); // fix for UPC Wien
00071                            if (p && p > pn) {
00072                               *p++ = 0;
00073                               strcpy(ShortNameBuf, skipspace(p));
00074                               }
00075                            }
00076                         // Avoid ',' in short name (would cause trouble in channels.conf):
00077                         for (char *p = ShortNameBuf; *p; p++) {
00078                             if (*p == ',')
00079                                *p = '.';
00080                             }
00081                         sd->providerName.getText(ProviderNameBuf, sizeof(ProviderNameBuf));
00082                         char *pp = compactspace(ProviderNameBuf);
00083                         if (channel) {
00084                            channel->SetId(sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
00085                            if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
00086                               channel->SetName(pn, ps, pp);
00087                            // Using SiSdtService.getFreeCaMode() is no good, because some
00088                            // tv stations set this flag even for non-encrypted channels :-(
00089                            // The special value 0xFFFF was supposed to mean "unknown encryption"
00090                            // and would have been overwritten with real CA values later:
00091                            // channel->SetCa(SiSdtService.getFreeCaMode() ? 0xFFFF : 0);
00092                            }
00093                         else if (*pn && Setup.UpdateChannels >= 4) {
00094                            channel = Channels.NewChannel(Channel(), pn, ps, pp, sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
00095                            patFilter->Trigger();
00096                            }
00097                         }
00098                    default: ;
00099                    }
00100                  }
00101                  break;
00102             // Using the CaIdentifierDescriptor is no good, because some tv stations
00103             // just don't use it. The actual CA values are collected in pat.c:
00104             /*
00105             case SI::CaIdentifierDescriptorTag: {
00106                  SI::CaIdentifierDescriptor *cid = (SI::CaIdentifierDescriptor *)d;
00107                  if (channel) {
00108                     for (SI::Loop::Iterator it; cid->identifiers.hasNext(it); )
00109                         channel->SetCa(cid->identifiers.getNext(it));
00110                     }
00111                  }
00112                  break;
00113             */
00114             case SI::NVODReferenceDescriptorTag: {
00115                  SI::NVODReferenceDescriptor *nrd = (SI::NVODReferenceDescriptor *)d;
00116                  SI::NVODReferenceDescriptor::Service Service;
00117                  for (SI::Loop::Iterator it; nrd->serviceLoop.getNext(Service, it); ) {
00118                      cChannel *link = Channels.GetByChannelID(tChannelID(Source(), Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId()));
00119                      if (!link && Setup.UpdateChannels >= 4) {
00120                         link = Channels.NewChannel(Channel(), "NVOD", "", "", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId());
00121                         patFilter->Trigger();
00122                         }
00123                      if (link) {
00124                         if (!LinkChannels)
00125                            LinkChannels = new cLinkChannels;
00126                         LinkChannels->Add(new cLinkChannel(link));
00127                         }
00128                      }
00129                  }
00130                  break;
00131             default: ;
00132             }
00133           delete d;
00134           }
00135       if (LinkChannels) {
00136          if (channel)
00137             channel->SetLinkChannels(LinkChannels);
00138          else
00139             delete LinkChannels;
00140          }
00141       }
00142   Channels.Unlock();
00143 }