|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <stdio.h> 00022 #include <errno.h> 00023 #include <sys/ioctl.h> 00024 #include <sys/time.h> 00025 #include <dlfcn.h> 00026 00027 #include <vdr/channels.h> 00028 #include <vdr/ci.h> 00029 #include <vdr/dvbdevice.h> 00030 #include <vdr/thread.h> 00031 00032 #ifndef SASC 00033 #include <vdr/dvbci.h> 00034 #include "FFdecsa/FFdecsa.h" 00035 #endif //!SASC 00036 00037 #include "device.h" 00038 #include "cam.h" 00039 #include "scsetup.h" 00040 #include "system.h" 00041 #include "data.h" 00042 #include "override.h" 00043 #include "misc.h" 00044 #include "log-core.h" 00045 00046 // -- cDeCsaTSBuffer ----------------------------------------------------------- 00047 00048 #ifndef SASC 00049 00050 cDeCsaTSBuffer::cDeCsaTSBuffer(int File, int Size, int CardIndex, cDeCSA *DeCsa, bool ScActive) 00051 { 00052 SetDescription("TS buffer on device %d", CardIndex); 00053 f=File; size=Size; cardIndex=CardIndex; decsa=DeCsa; 00054 delivered=false; 00055 ringBuffer=new cRingBufferLinear(Size,TS_SIZE,true,"FFdecsa-TS"); 00056 ringBuffer->SetTimeouts(100,100); 00057 if(decsa) decsa->SetActive(true); 00058 SetActive(ScActive); 00059 Start(); 00060 } 00061 00062 cDeCsaTSBuffer::~cDeCsaTSBuffer() 00063 { 00064 Cancel(3); 00065 if(decsa) decsa->SetActive(false); 00066 delete ringBuffer; 00067 } 00068 00069 void cDeCsaTSBuffer::SetActive(bool ScActive) 00070 { 00071 scActive=ScActive; 00072 } 00073 00074 void cDeCsaTSBuffer::Action(void) 00075 { 00076 if(ringBuffer) { 00077 bool firstRead=true; 00078 cPoller Poller(f); 00079 while(Running()) { 00080 if(firstRead || Poller.Poll(100)) { 00081 firstRead=false; 00082 int r=ringBuffer->Read(f); 00083 if(r<0 && FATALERRNO) { 00084 if(errno==EOVERFLOW) 00085 esyslog("ERROR: driver buffer overflow on device %d",cardIndex); 00086 else { LOG_ERROR; break; } 00087 } 00088 } 00089 } 00090 } 00091 } 00092 00093 uchar *cDeCsaTSBuffer::Get(void) 00094 { 00095 int Count=0; 00096 if(delivered) { ringBuffer->Del(TS_SIZE); delivered=false; } 00097 uchar *p=ringBuffer->Get(Count); 00098 if(p && Count>=TS_SIZE) { 00099 if(*p!=TS_SYNC_BYTE) { 00100 for(int i=1; i<Count; i++) 00101 if(p[i]==TS_SYNC_BYTE && 00102 (i+TS_SIZE==Count || (i+TS_SIZE>Count && p[i+TS_SIZE]==TS_SYNC_BYTE)) ) { Count=i; break; } 00103 ringBuffer->Del(Count); 00104 esyslog("ERROR: skipped %d bytes to sync on TS packet on device %d",Count,cardIndex); 00105 return NULL; 00106 } 00107 00108 if(scActive && (p[3]&0xC0)) { 00109 if(decsa) { 00110 if(!decsa->Decrypt(p,Count,false)) { 00111 cCondWait::SleepMs(20); 00112 return NULL; 00113 } 00114 } 00115 else p[3]&=~0xC0; // FF hack 00116 } 00117 00118 delivered=true; 00119 return p; 00120 } 00121 return NULL; 00122 } 00123 00124 #endif //!SASC 00125 00126 // --- cScDevicePlugin --------------------------------------------------------- 00127 00128 static cSimpleList<cScDevicePlugin> devplugins; 00129 00130 cScDevicePlugin::cScDevicePlugin(void) 00131 { 00132 devplugins.Add(this); 00133 } 00134 00135 cScDevicePlugin::~cScDevicePlugin() 00136 { 00137 devplugins.Del(this,false); 00138 } 00139 00140 // -- cScDvbDevice ------------------------------------------------------------- 00141 00142 #ifndef SASC 00143 00144 #define SCDEVICE cScDvbDevice 00145 #define DVBDEVICE cDvbDevice 00146 #if APIVERSNUM < 10711 00147 #define OWN_FULLTS 00148 #define OWN_SETCA 00149 #endif 00150 #include "device-tmpl.c" 00151 00152 #if APIVERSNUM < 10711 00153 bool cScDvbDevice::CheckFullTs(void) 00154 { 00155 return IsPrimaryDevice() && HasDecoder(); 00156 } 00157 00158 bool cScDvbDevice::SetCaDescr(ca_descr_t *ca_descr, bool initial) 00159 { 00160 cMutexLock lock(&cafdMutex); 00161 return ioctl(fd_ca,CA_SET_DESCR,ca_descr)>=0; 00162 } 00163 00164 bool cScDvbDevice::SetCaPid(ca_pid_t *ca_pid) 00165 { 00166 cMutexLock lock(&cafdMutex); 00167 return ioctl(fd_ca,CA_SET_PID,ca_pid)>=0; 00168 } 00169 #endif //APIVERSNUM < 10711 00170 00171 // -- cScDvbDevicePlugin ------------------------------------------------------- 00172 00173 class cScDvbDevicePlugin : public cScDevicePlugin { 00174 public: 00175 virtual cDevice *Probe(int Adapter, int Frontend, uint32_t SubSystemId); 00176 virtual bool LateInit(cDevice *dev); 00177 virtual bool EarlyShutdown(cDevice *dev); 00178 #if APIVERSNUM < 10711 00179 virtual bool SetCaDescr(cDevice *dev, ca_descr_t *ca_descr, bool initial); 00180 virtual bool SetCaPid(cDevice *dev, ca_pid_t *ca_pid); 00181 #endif 00182 }; 00183 00184 cDevice *cScDvbDevicePlugin::Probe(int Adapter, int Frontend, uint32_t SubSystemId) 00185 { 00186 PRINTF(L_GEN_DEBUG,"creating standard device %d/%d",Adapter,Frontend); 00187 return new cScDvbDevice(this,Adapter,Frontend,cScDevices::DvbOpen(DEV_DVB_CA,Adapter,Frontend,O_RDWR)); 00188 } 00189 00190 bool cScDvbDevicePlugin::LateInit(cDevice *dev) 00191 { 00192 cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev); 00193 if(d) d->LateInit(); 00194 return d!=0; 00195 } 00196 00197 bool cScDvbDevicePlugin::EarlyShutdown(cDevice *dev) 00198 { 00199 cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev); 00200 if(d) d->EarlyShutdown(); 00201 return d!=0; 00202 } 00203 00204 #if APIVERSNUM < 10711 00205 bool cScDvbDevicePlugin::SetCaDescr(cDevice *dev, ca_descr_t *ca_descr, bool initial) 00206 { 00207 cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev); 00208 if(d) return d->SetCaDescr(ca_descr,initial); 00209 return false; 00210 } 00211 00212 bool cScDvbDevicePlugin::SetCaPid(cDevice *dev, ca_pid_t *ca_pid) 00213 { 00214 cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev); 00215 if(d) return d->SetCaPid(ca_pid); 00216 return d!=0; 00217 } 00218 #endif //APIVERSNUM < 10711 00219 00220 // --- cScDeviceProbe ---------------------------------------------------------- 00221 00222 #if APIVERSNUM >= 10711 00223 00224 class cScDeviceProbe : public cDvbDeviceProbe { 00225 private: 00226 static cScDeviceProbe *probe; 00227 public: 00228 virtual bool Probe(int Adapter, int Frontend); 00229 static void Install(void); 00230 static void Remove(void); 00231 #if APIVERSNUM < 10719 00232 uint32_t GetSubsystemId(int Adapter, int Frontend); 00233 #endif 00234 }; 00235 00236 cScDeviceProbe *cScDeviceProbe::probe=0; 00237 00238 void cScDeviceProbe::Install(void) 00239 { 00240 if(!probe) probe=new cScDeviceProbe; 00241 } 00242 00243 void cScDeviceProbe::Remove(void) 00244 { 00245 delete probe; probe=0; 00246 } 00247 00248 bool cScDeviceProbe::Probe(int Adapter, int Frontend) 00249 { 00250 uint32_t subid=GetSubsystemId(Adapter,Frontend); 00251 PRINTF(L_GEN_DEBUG,"capturing device %d/%d (subsystem ID %08x)",Adapter,Frontend,subid); 00252 for(cScDevicePlugin *dp=devplugins.First(); dp; dp=devplugins.Next(dp)) 00253 if(dp->Probe(Adapter,Frontend,subid)) return true; 00254 return false; 00255 } 00256 00257 #if APIVERSNUM < 10719 00258 uint32_t cScDeviceProbe::GetSubsystemId(int Adapter, int Frontend) 00259 { 00260 cString FileName; 00261 cReadLine ReadLine; 00262 FILE *f = NULL; 00263 uint32_t SubsystemId = 0; 00264 FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend); 00265 if ((f = fopen(FileName, "r")) != NULL) { 00266 if (char *s = ReadLine.Read(f)) 00267 SubsystemId = strtoul(s, NULL, 0) << 16; 00268 fclose(f); 00269 } 00270 FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend); 00271 if ((f = fopen(FileName, "r")) != NULL) { 00272 if (char *s = ReadLine.Read(f)) 00273 SubsystemId |= strtoul(s, NULL, 0); 00274 fclose(f); 00275 } 00276 return SubsystemId; 00277 } 00278 #endif //APIVERSNUM < 10719 00279 00280 #endif //APIVERSNUM >= 10711 00281 00282 #endif //!SASC 00283 00284 // -- cScDevices --------------------------------------------------------------- 00285 00286 int cScDevices::budget=0; 00287 00288 void cScDevices::DvbName(const char *Name, int a, int f, char *buffer, int len) 00289 { 00290 snprintf(buffer,len,"%s%d/%s%d",DEV_DVB_ADAPTER,a,Name,f); 00291 } 00292 00293 int cScDevices::DvbOpen(const char *Name, int a, int f, int Mode, bool ReportError) 00294 { 00295 char FileName[128]; 00296 DvbName(Name,a,f,FileName,sizeof(FileName)); 00297 int fd=open(FileName,Mode); 00298 if(fd<0 && ReportError) LOG_ERROR_STR(FileName); 00299 return fd; 00300 } 00301 00302 #ifndef SASC 00303 00304 #if APIVERSNUM < 10711 00305 static int *vdr_nci=0, *vdr_ud=0, vdr_save_ud; 00306 #endif 00307 00308 void cScDevices::OnPluginLoad(void) 00309 { 00310 #if APIVERSNUM >= 10711 00311 PRINTF(L_GEN_DEBUG,"using new 1.7.11+ capture code"); 00312 cScDeviceProbe::Install(); 00313 #else 00314 PRINTF(L_GEN_DEBUG,"using old pre1.7.11 capture code"); 00315 /* 00316 This is an extremly ugly hack to access VDRs device scan parameters, which are 00317 protected in this context. Heavily dependant on the actual symbol names 00318 created by the compiler. May fail in any future version! 00319 00320 To get the actual symbol names of your VDR binary you may use the command: 00321 objdump -T <path-to-vdr>/vdr | grep -E "(useDevice|nextCardIndex)" 00322 Insert the symbol names below. 00323 */ 00324 #if __GNUC__ >= 3 00325 vdr_nci=(int *)dlsym(RTLD_DEFAULT,"_ZN7cDevice13nextCardIndexE"); 00326 vdr_ud =(int *)dlsym(RTLD_DEFAULT,"_ZN7cDevice9useDeviceE"); 00327 #else 00328 vdr_nci=(int *)dlsym(RTLD_DEFAULT,"_7cDevice.nextCardIndex"); 00329 vdr_ud =(int *)dlsym(RTLD_DEFAULT,"_7cDevice.useDevice"); 00330 #endif 00331 if(vdr_nci && vdr_ud) { vdr_save_ud=*vdr_ud; *vdr_ud=1<<30; } 00332 #endif 00333 // default device plugin must be last in the list 00334 new cScDvbDevicePlugin; 00335 } 00336 00337 void cScDevices::OnPluginUnload(void) 00338 { 00339 #if APIVERSNUM >= 10711 00340 cScDeviceProbe::Remove(); 00341 #endif 00342 } 00343 00344 bool cScDevices::Initialize(void) 00345 { 00346 #if APIVERSNUM >= 10711 00347 return true; 00348 #else 00349 if(!vdr_nci || !vdr_ud) { 00350 PRINTF(L_GEN_ERROR,"Failed to locate VDR symbols. Plugin not operable"); 00351 return false; 00352 } 00353 if(NumDevices()>0) { 00354 PRINTF(L_GEN_ERROR,"Number of devices != 0 on init. Put SC plugin first on VDR commandline! Aborting."); 00355 return false; 00356 } 00357 *vdr_nci=0; *vdr_ud=vdr_save_ud; 00358 00359 int i, found=0; 00360 for(i=0; i<MAXDVBDEVICES; i++) { 00361 if(UseDevice(NextCardIndex())) { 00362 char name[128]; 00363 cScDevices::DvbName(DEV_DVB_FRONTEND,i,0,name,sizeof(name)); 00364 if(access(name,F_OK)==0) { 00365 PRINTF(L_GEN_DEBUG,"probing %s",name); 00366 int f=open(name,O_RDONLY); 00367 if(f>=0) { 00368 close(f); 00369 PRINTF(L_GEN_DEBUG,"capturing device %d",i); 00370 devplugins.First()->Probe(i,0,0); 00371 found++; 00372 } 00373 else { 00374 if(errno!=ENODEV && errno!=EINVAL) PRINTF(L_GEN_ERROR,"open %s failed: %s",name,strerror(errno)); 00375 break; 00376 } 00377 } 00378 else { 00379 if(errno!=ENOENT) PRINTF(L_GEN_ERROR,"access %s failed: %s",name,strerror(errno)); 00380 break; 00381 } 00382 } 00383 else NextCardIndex(1); 00384 } 00385 NextCardIndex(MAXDVBDEVICES-i); 00386 if(found>0) PRINTF(L_GEN_INFO,"captured %d video device%s",found,found>1 ? "s" : ""); 00387 else PRINTF(L_GEN_INFO,"no DVB device captured"); 00388 return found>0; 00389 #endif 00390 } 00391 00392 void cScDevices::Startup(void) 00393 { 00394 if(ScSetup.ForceTransfer) 00395 SetTransferModeForDolbyDigital(2); 00396 for(int n=cDevice::NumDevices(); --n>=0;) { 00397 cDevice *dev=cDevice::GetDevice(n); 00398 for(cScDevicePlugin *dp=devplugins.First(); dp; dp=devplugins.Next(dp)) 00399 if(dp->LateInit(dev)) break; 00400 } 00401 } 00402 00403 void cScDevices::Shutdown(void) 00404 { 00405 for(int n=cDevice::NumDevices(); --n>=0;) { 00406 cDevice *dev=cDevice::GetDevice(n); 00407 for(cScDevicePlugin *dp=devplugins.First(); dp; dp=devplugins.Next(dp)) 00408 if(dp->EarlyShutdown(dev)) break; 00409 } 00410 } 00411 00412 void cScDevices::SetForceBudget(int n) 00413 { 00414 if(n>=0 && n<MAXDVBDEVICES) budget|=(1<<n); 00415 } 00416 00417 bool cScDevices::ForceBudget(int n) 00418 { 00419 return budget && (budget&(1<<n)); 00420 } 00421 00422 #else //!SASC 00423 00424 void cScDevices::OnPluginLoad(void) {} 00425 void cScDevices::OnPluginUnload(void) {} 00426 bool cScDevices::Initialize(void) { return true; } 00427 void cScDevices::Startup(void) {} 00428 void cScDevices::Shutdown(void) {} 00429 void cScDevices::SetForceBudget(int n) {} 00430 bool cScDevices::ForceBudget(int n) { return true; } 00431 00432 #endif //!SASC