vdr-1.4.7/dvbdevice.c

Go to the documentation of this file.
00001 /*
00002  * dvbdevice.c: The DVB device interface
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: dvbdevice.c 1.160.1.1 2007/02/24 11:10:14 kls Exp $
00008  */
00009 
00010 #include "dvbdevice.h"
00011 #include <errno.h>
00012 #include <limits.h>
00013 #include <linux/videodev.h>
00014 #include <linux/dvb/audio.h>
00015 #include <linux/dvb/dmx.h>
00016 #include <linux/dvb/frontend.h>
00017 #include <linux/dvb/video.h>
00018 #include <sys/ioctl.h>
00019 #include <sys/mman.h>
00020 #include "channels.h"
00021 #include "diseqc.h"
00022 #include "dvbosd.h"
00023 #include "eitscan.h"
00024 #include "player.h"
00025 #include "receiver.h"
00026 #include "status.h"
00027 #include "transfer.h"
00028 
00029 #define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
00030 #define DO_MULTIPLE_RECORDINGS 1
00031 //#define DO_MULTIPLE_CA_CHANNELS
00032 
00033 #define DEV_VIDEO         "/dev/video"
00034 #define DEV_DVB_ADAPTER   "/dev/dvb/adapter"
00035 #define DEV_DVB_OSD       "osd"
00036 #define DEV_DVB_FRONTEND  "frontend"
00037 #define DEV_DVB_DVR       "dvr"
00038 #define DEV_DVB_DEMUX     "demux"
00039 #define DEV_DVB_VIDEO     "video"
00040 #define DEV_DVB_AUDIO     "audio"
00041 #define DEV_DVB_CA        "ca"
00042 
00043 #define DVBS_TUNE_TIMEOUT  9000 //ms
00044 #define DVBS_LOCK_TIMEOUT  2000 //ms
00045 #define DVBC_TUNE_TIMEOUT  9000 //ms
00046 #define DVBC_LOCK_TIMEOUT  2000 //ms
00047 #define DVBT_TUNE_TIMEOUT  9000 //ms
00048 #define DVBT_LOCK_TIMEOUT  2000 //ms
00049 
00050 class cDvbName {
00051 private:
00052   char buffer[PATH_MAX];
00053 public:
00054   cDvbName(const char *Name, int n) {
00055     snprintf(buffer, sizeof(buffer), "%s%d/%s%d", DEV_DVB_ADAPTER, n, Name, 0);
00056     }
00057   const char *operator*() { return buffer; }
00058   };
00059 
00060 static int DvbOpen(const char *Name, int n, int Mode, bool ReportError = false)
00061 {
00062   const char *FileName = *cDvbName(Name, n);
00063   int fd = open(FileName, Mode);
00064   if (fd < 0 && ReportError)
00065      LOG_ERROR_STR(FileName);
00066   return fd;
00067 }
00068 
00069 // --- cDvbTuner -------------------------------------------------------------
00070 
00071 class cDvbTuner : public cThread {
00072 private:
00073   enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
00074   int fd_frontend;
00075   int cardIndex;
00076   int tuneTimeout;
00077   int lockTimeout;
00078   time_t lastTimeoutReport;
00079   fe_type_t frontendType;
00080   cCiHandler *ciHandler;
00081   cChannel channel;
00082   const char *diseqcCommands;
00083   eTunerStatus tunerStatus;
00084   cMutex mutex;
00085   cCondVar locked;
00086   cCondVar newSet;
00087   bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0);
00088   bool SetFrontend(void);
00089   virtual void Action(void);
00090 public:
00091   cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler);
00092   virtual ~cDvbTuner();
00093   bool IsTunedTo(const cChannel *Channel) const;
00094   void Set(const cChannel *Channel, bool Tune);
00095   bool Locked(int TimeoutMs = 0);
00096   };
00097 
00098 cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler)
00099 {
00100   fd_frontend = Fd_Frontend;
00101   cardIndex = CardIndex;
00102   frontendType = FrontendType;
00103   ciHandler = CiHandler;
00104   tuneTimeout = 0;
00105   lockTimeout = 0;
00106   lastTimeoutReport = 0;
00107   diseqcCommands = NULL;
00108   tunerStatus = tsIdle;
00109   if (frontendType == FE_QPSK)
00110      CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
00111   SetDescription("tuner on device %d", cardIndex + 1);
00112   Start();
00113 }
00114 
00115 cDvbTuner::~cDvbTuner()
00116 {
00117   tunerStatus = tsIdle;
00118   newSet.Broadcast();
00119   locked.Broadcast();
00120   Cancel(3);
00121 }
00122 
00123 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
00124 {
00125   return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Transponder() == Channel->Transponder();
00126 }
00127 
00128 void cDvbTuner::Set(const cChannel *Channel, bool Tune)
00129 {
00130   cMutexLock MutexLock(&mutex);
00131   if (Tune)
00132      tunerStatus = tsSet;
00133   channel = *Channel;
00134   lastTimeoutReport = 0;
00135   newSet.Broadcast();
00136 }
00137 
00138 bool cDvbTuner::Locked(int TimeoutMs)
00139 {
00140   bool isLocked = (tunerStatus >= tsLocked);
00141   if (isLocked || !TimeoutMs)
00142      return isLocked;
00143 
00144   cMutexLock MutexLock(&mutex);
00145   if (TimeoutMs && tunerStatus < tsLocked)
00146      locked.TimedWait(mutex, TimeoutMs);
00147   return tunerStatus >= tsLocked;
00148 }
00149 
00150 bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs)
00151 {
00152   if (TimeoutMs) {
00153      cPoller Poller(fd_frontend);
00154      if (Poller.Poll(TimeoutMs)) {
00155         dvb_frontend_event Event;
00156         while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
00157               ; // just to clear the event queue - we'll read the actual status below
00158         }
00159      }
00160   while (1) {
00161         int stat = ioctl(fd_frontend, FE_READ_STATUS, &Status);
00162         if (stat == 0)
00163            return true;
00164         if (stat < 0 && errno == EINTR)
00165            continue;
00166         break;
00167         }
00168   return false;
00169 }
00170 
00171 static unsigned int FrequencyToHz(unsigned int f)
00172 {
00173   while (f && f < 1000000)
00174         f *= 1000;
00175   return f;
00176 }
00177 
00178 bool cDvbTuner::SetFrontend(void)
00179 {
00180   dvb_frontend_parameters Frontend;
00181 
00182   memset(&Frontend, 0, sizeof(Frontend));
00183 
00184   switch (frontendType) {
00185     case FE_QPSK: { // DVB-S
00186 
00187          unsigned int frequency = channel.Frequency();
00188 
00189          if (Setup.DiSEqC) {
00190             cDiseqc *diseqc = Diseqcs.Get(channel.Source(), channel.Frequency(), channel.Polarization());
00191             if (diseqc) {
00192                if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) {
00193                   cDiseqc::eDiseqcActions da;
00194                   for (char *CurrentAction = NULL; (da = diseqc->Execute(&CurrentAction)) != cDiseqc::daNone; ) {
00195                       switch (da) {
00196                         case cDiseqc::daNone:      break;
00197                         case cDiseqc::daToneOff:   CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
00198                         case cDiseqc::daToneOn:    CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
00199                         case cDiseqc::daVoltage13: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
00200                         case cDiseqc::daVoltage18: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
00201                         case cDiseqc::daMiniA:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
00202                         case cDiseqc::daMiniB:     CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
00203                         case cDiseqc::daCodes: {
00204                              int n = 0;
00205                              uchar *codes = diseqc->Codes(n);
00206                              if (codes) {
00207                                 struct dvb_diseqc_master_cmd cmd;
00208                                 memcpy(cmd.msg, codes, min(n, int(sizeof(cmd.msg))));
00209                                 cmd.msg_len = n;
00210                                 CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd));
00211                                 }
00212                              }
00213                              break;
00214                         }
00215                       }
00216                   diseqcCommands = diseqc->Commands();
00217                   }
00218                frequency -= diseqc->Lof();
00219                }
00220             else {
00221                esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number());
00222                return false;
00223                }
00224             }
00225          else {
00226             int tone = SEC_TONE_OFF;
00227 
00228             if (frequency < (unsigned int)Setup.LnbSLOF) {
00229                frequency -= Setup.LnbFrequLo;
00230                tone = SEC_TONE_OFF;
00231                }
00232             else {
00233                frequency -= Setup.LnbFrequHi;
00234                tone = SEC_TONE_ON;
00235                }
00236             int volt = (channel.Polarization() == 'v' || channel.Polarization() == 'V' || channel.Polarization() == 'r' || channel.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
00237             CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
00238             CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
00239             }
00240 
00241          frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF
00242          Frontend.frequency = frequency * 1000UL;
00243          Frontend.inversion = fe_spectral_inversion_t(channel.Inversion());
00244          Frontend.u.qpsk.symbol_rate = channel.Srate() * 1000UL;
00245          Frontend.u.qpsk.fec_inner = fe_code_rate_t(channel.CoderateH());
00246 
00247          tuneTimeout = DVBS_TUNE_TIMEOUT;
00248          lockTimeout = DVBS_LOCK_TIMEOUT;
00249          }
00250          break;
00251     case FE_QAM: { // DVB-C
00252 
00253          // Frequency and symbol rate:
00254 
00255          Frontend.frequency = FrequencyToHz(channel.Frequency());
00256          Frontend.inversion = fe_spectral_inversion_t(channel.Inversion());
00257          Frontend.u.qam.symbol_rate = channel.Srate() * 1000UL;
00258          Frontend.u.qam.fec_inner = fe_code_rate_t(channel.CoderateH());
00259          Frontend.u.qam.modulation = fe_modulation_t(channel.Modulation());
00260 
00261          tuneTimeout = DVBC_TUNE_TIMEOUT;
00262          lockTimeout = DVBC_LOCK_TIMEOUT;
00263          }
00264          break;
00265     case FE_OFDM: { // DVB-T
00266 
00267          // Frequency and OFDM paramaters:
00268 
00269          Frontend.frequency = FrequencyToHz(channel.Frequency());
00270          Frontend.inversion = fe_spectral_inversion_t(channel.Inversion());
00271          Frontend.u.ofdm.bandwidth = fe_bandwidth_t(channel.Bandwidth());
00272          Frontend.u.ofdm.code_rate_HP = fe_code_rate_t(channel.CoderateH());
00273          Frontend.u.ofdm.code_rate_LP = fe_code_rate_t(channel.CoderateL());
00274          Frontend.u.ofdm.constellation = fe_modulation_t(channel.Modulation());
00275          Frontend.u.ofdm.transmission_mode = fe_transmit_mode_t(channel.Transmission());
00276          Frontend.u.ofdm.guard_interval = fe_guard_interval_t(channel.Guard());
00277          Frontend.u.ofdm.hierarchy_information = fe_hierarchy_t(channel.Hierarchy());
00278 
00279          tuneTimeout = DVBT_TUNE_TIMEOUT;
00280          lockTimeout = DVBT_LOCK_TIMEOUT;
00281          }
00282          break;
00283     default:
00284          esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
00285          return false;
00286     }
00287   if (ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend) < 0) {
00288      esyslog("ERROR: frontend %d: %m", cardIndex);
00289      return false;
00290      }
00291   return true;
00292 }
00293 
00294 void cDvbTuner::Action(void)
00295 {
00296   cTimeMs Timer;
00297   bool LostLock = false;
00298   fe_status_t Status = (fe_status_t)0;
00299   while (Running()) {
00300         fe_status_t NewStatus;
00301         if (GetFrontendStatus(NewStatus, 10))
00302            Status = NewStatus;
00303         cMutexLock MutexLock(&mutex);
00304         switch (tunerStatus) {
00305           case tsIdle:
00306                break;
00307           case tsSet:
00308                tunerStatus = SetFrontend() ? tsTuned : tsIdle;
00309                Timer.Set(tuneTimeout);
00310                continue;
00311           case tsTuned:
00312                if (Timer.TimedOut()) {
00313                   tunerStatus = tsSet;
00314                   diseqcCommands = NULL;
00315                   if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
00316                      isyslog("frontend %d timed out while tuning to channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
00317                      lastTimeoutReport = time(NULL);
00318                      }
00319                   continue;
00320                   }
00321           case tsLocked:
00322                if (Status & FE_REINIT) {
00323                   tunerStatus = tsSet;
00324                   diseqcCommands = NULL;
00325                   isyslog("frontend %d was reinitialized", cardIndex);
00326                   lastTimeoutReport = 0;
00327                   continue;
00328                   }
00329                else if (Status & FE_HAS_LOCK) {
00330                   if (LostLock) {
00331                      isyslog("frontend %d regained lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
00332                      LostLock = false;
00333                      }
00334                   tunerStatus = tsLocked;
00335                   locked.Broadcast();
00336                   lastTimeoutReport = 0;
00337                   }
00338                else if (tunerStatus == tsLocked) {
00339                   LostLock = true;
00340                   isyslog("frontend %d lost lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
00341                   tunerStatus = tsTuned;
00342                   Timer.Set(lockTimeout);
00343                   lastTimeoutReport = 0;
00344                   continue;
00345                   }
00346           }
00347 
00348         if (ciHandler)
00349            ciHandler->Process();
00350         if (tunerStatus != tsTuned)
00351            newSet.TimedWait(mutex, 1000);
00352         }
00353 }
00354 
00355 // --- cDvbDevice ------------------------------------------------------------
00356 
00357 int cDvbDevice::devVideoOffset = -1;
00358 int cDvbDevice::setTransferModeForDolbyDigital = 1;
00359 
00360 cDvbDevice::cDvbDevice(int n)
00361 {
00362   dvbTuner = NULL;
00363   frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
00364   spuDecoder = NULL;
00365   digitalAudio = false;
00366   playMode = pmNone;
00367 
00368   // Devices that are present on all card types:
00369 
00370   int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK);
00371 
00372   // Devices that are only present on cards with decoders:
00373 
00374   fd_osd      = DvbOpen(DEV_DVB_OSD,    n, O_RDWR);
00375   fd_video    = DvbOpen(DEV_DVB_VIDEO,  n, O_RDWR | O_NONBLOCK);
00376   fd_audio    = DvbOpen(DEV_DVB_AUDIO,  n, O_RDWR | O_NONBLOCK);
00377   fd_stc      = DvbOpen(DEV_DVB_DEMUX,  n, O_RDWR);
00378 
00379   // The DVR device (will be opened and closed as needed):
00380 
00381   fd_dvr = -1;
00382 
00383   // The offset of the /dev/video devices:
00384 
00385   if (devVideoOffset < 0) { // the first one checks this
00386      FILE *f = NULL;
00387      char buffer[PATH_MAX];
00388      for (int ofs = 0; ofs < 100; ofs++) {
00389          snprintf(buffer, sizeof(buffer), "/proc/video/dev/video%d", ofs);
00390          if ((f = fopen(buffer, "r")) != NULL) {
00391             if (fgets(buffer, sizeof(buffer), f)) {
00392                if (strstr(buffer, "DVB Board")) { // found the _first_ DVB card
00393                   devVideoOffset = ofs;
00394                   dsyslog("video device offset is %d", devVideoOffset);
00395                   break;
00396                   }
00397                }
00398             else
00399                break;
00400             fclose(f);
00401             }
00402          else
00403             break;
00404          }
00405      if (devVideoOffset < 0)
00406         devVideoOffset = 0;
00407      if (f)
00408         fclose(f);
00409      }
00410   devVideoIndex = (devVideoOffset >= 0 && HasDecoder()) ? devVideoOffset++ : -1;
00411 
00412   // Video format:
00413 
00414   SetVideoFormat(Setup.VideoFormat);
00415 
00416   // We only check the devices that must be present - the others will be checked before accessing them://XXX
00417 
00418   if (fd_frontend >= 0) {
00419      dvb_frontend_info feinfo;
00420      if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) {
00421         frontendType = feinfo.type;
00422         ciHandler = cCiHandler::CreateCiHandler(*cDvbName(DEV_DVB_CA, n));
00423         dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType, ciHandler);
00424         }
00425      else
00426         LOG_ERROR;
00427      }
00428   else
00429      esyslog("ERROR: can't open DVB device %d", n);
00430 
00431   StartSectionHandler();
00432 }
00433 
00434 cDvbDevice::~cDvbDevice()
00435 {
00436   delete spuDecoder;
00437   delete dvbTuner;
00438   // We're not explicitly closing any device files here, since this sometimes
00439   // caused segfaults. Besides, the program is about to terminate anyway...
00440 }
00441 
00442 bool cDvbDevice::Probe(const char *FileName)
00443 {
00444   if (access(FileName, F_OK) == 0) {
00445      dsyslog("probing %s", FileName);
00446      int f = open(FileName, O_RDONLY);
00447      if (f >= 0) {
00448         close(f);
00449         return true;
00450         }
00451      else if (errno != ENODEV && errno != EINVAL)
00452         LOG_ERROR_STR(FileName);
00453      }
00454   else if (errno != ENOENT)
00455      LOG_ERROR_STR(FileName);
00456   return false;
00457 }
00458 
00459 bool cDvbDevice::Initialize(void)
00460 {
00461   int found = 0;
00462   int i;
00463   for (i = 0; i < MAXDVBDEVICES; i++) {
00464       if (UseDevice(NextCardIndex())) {
00465          if (Probe(*cDvbName(DEV_DVB_FRONTEND, i))) {
00466             new cDvbDevice(i);
00467             found++;
00468             }
00469          else
00470             break;
00471          }
00472       else
00473          NextCardIndex(1); // skips this one
00474       }
00475   NextCardIndex(MAXDVBDEVICES - i); // skips the rest
00476   if (found > 0)
00477      isyslog("found %d video device%s", found, found > 1 ? "s" : "");
00478   else
00479      isyslog("no DVB device found");
00480   return found > 0;
00481 }
00482 
00483 void cDvbDevice::MakePrimaryDevice(bool On)
00484 {
00485   if (HasDecoder())
00486      new cDvbOsdProvider(fd_osd);
00487 }
00488 
00489 bool cDvbDevice::HasDecoder(void) const
00490 {
00491   return fd_video >= 0 && fd_audio >= 0;
00492 }
00493 
00494 bool cDvbDevice::Ready(void)
00495 {
00496   if (ciHandler) {
00497      ciHandler->Process();
00498      return ciHandler->Ready();
00499      }
00500   return true;
00501 }
00502 
00503 int cDvbDevice::ProvidesCa(const cChannel *Channel) const
00504 {
00505   int NumCams = 0;
00506   if (ciHandler) {
00507      NumCams = ciHandler->NumCams();
00508      if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
00509         unsigned short ids[MAXCAIDS + 1];
00510         for (int i = 0; i <= MAXCAIDS; i++) // '<=' copies the terminating 0!
00511             ids[i] = Channel->Ca(i);
00512         if (ciHandler->ProvidesCa(ids))
00513            return NumCams + 1;
00514         }
00515      }
00516   int result = cDevice::ProvidesCa(Channel);
00517   if (result > 0)
00518      result += NumCams;
00519   return result;
00520 }
00521 
00522 cSpuDecoder *cDvbDevice::GetSpuDecoder(void)
00523 {
00524   if (!spuDecoder && IsPrimaryDevice())
00525      spuDecoder = new cDvbSpuDecoder();
00526   return spuDecoder;
00527 }
00528 
00529 uchar *cDvbDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
00530 {
00531   if (devVideoIndex < 0)
00532      return NULL;
00533   char buffer[PATH_MAX];
00534   snprintf(buffer, sizeof(buffer), "%s%d", DEV_VIDEO, devVideoIndex);
00535   int videoDev = open(buffer, O_RDWR);
00536   if (videoDev >= 0) {
00537      uchar *result = NULL;
00538      struct video_mbuf mbuf;
00539      if (ioctl(videoDev, VIDIOCGMBUF, &mbuf) == 0) {
00540         int msize = mbuf.size;
00541         unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
00542         if (mem && mem != (unsigned char *)-1) {
00543            // set up the size and RGB
00544            struct video_capability vc;
00545            if (ioctl(videoDev, VIDIOCGCAP, &vc) == 0) {
00546               struct video_mmap vm;
00547               vm.frame = 0;
00548               if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
00549                   (SizeY > 0) && (SizeY <= vc.maxheight)) {
00550                  vm.width = SizeX;
00551                  vm.height = SizeY;
00552                  }
00553               else {
00554                  vm.width = vc.maxwidth;
00555                  vm.height = vc.maxheight;
00556                  }
00557               vm.format = VIDEO_PALETTE_RGB24;
00558               if (ioctl(videoDev, VIDIOCMCAPTURE, &vm) == 0 && ioctl(videoDev, VIDIOCSYNC, &vm.frame) == 0) {
00559                  // make RGB out of BGR:
00560                  int memsize = vm.width * vm.height;
00561                  unsigned char *mem1 = mem;
00562                  for (int i = 0; i < memsize; i++) {
00563                      unsigned char tmp = mem1[2];
00564                      mem1[2] = mem1[0];
00565                      mem1[0] = tmp;
00566                      mem1 += 3;
00567                      }
00568 
00569                  if (Quality < 0)
00570                     Quality = 100;
00571 
00572                  dsyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
00573                  if (Jpeg) {
00574                     // convert to JPEG:
00575                     result = RgbToJpeg(mem, vm.width, vm.height, Size, Quality);
00576                     if (!result)
00577                        esyslog("ERROR: failed to convert image to JPEG");
00578                     }
00579                  else {
00580                     // convert to PNM:
00581                     char buf[32];
00582                     snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", vm.width, vm.height);
00583                     int l = strlen(buf);
00584                     int bytes = memsize * 3;
00585                     Size = l + bytes;
00586                     result = MALLOC(uchar, Size);
00587                     if (result) {
00588                        memcpy(result, buf, l);
00589                        memcpy(result + l, mem, bytes);
00590                        }
00591                     else
00592                        esyslog("ERROR: failed to convert image to PNM");
00593                     }
00594                  }
00595               }
00596            munmap(mem, msize);
00597            }
00598         else
00599            esyslog("ERROR: failed to memmap video device");
00600         }
00601      close(videoDev);
00602      return result;
00603      }
00604   else
00605      LOG_ERROR_STR(buffer);
00606   return NULL;
00607 }
00608 
00609 void cDvbDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
00610 {
00611   cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
00612   if (HasDecoder()) {
00613      if (Setup.VideoFormat) {
00614         CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX));
00615         }
00616      else {
00617         switch (VideoDisplayFormat) {
00618           case vdfPanAndScan:
00619                CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_PAN_SCAN));
00620                break;
00621           case vdfLetterBox:
00622                CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX));
00623                break;
00624           case vdfCenterCutOut:
00625                CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_CENTER_CUT_OUT));
00626                break;
00627           }
00628         }
00629      }
00630 }
00631 
00632 void cDvbDevice::SetVideoFormat(bool VideoFormat16_9)
00633 {
00634   if (HasDecoder()) {
00635      CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, VideoFormat16_9 ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3));
00636      SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
00637      }
00638 }
00639 
00640 eVideoSystem cDvbDevice::GetVideoSystem(void)
00641 {
00642   eVideoSystem VideoSystem = vsPAL;
00643   video_size_t vs;
00644   if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
00645      if (vs.h == 480 || vs.h == 240)
00646         VideoSystem = vsNTSC;
00647      }
00648   else
00649      LOG_ERROR;
00650   return VideoSystem;
00651 }
00652 
00653 bool cDvbDevice::SetAudioBypass(bool On)
00654 {
00655   if (setTransferModeForDolbyDigital != 1)
00656      return false;
00657   return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
00658 }
00659 
00660 //                            ptAudio        ptVideo        ptPcr        ptTeletext        ptDolby        ptOther
00661 dmx_pes_type_t PesTypes[] = { DMX_PES_AUDIO, DMX_PES_VIDEO, DMX_PES_PCR, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
00662 
00663 bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
00664 {
00665   if (Handle->pid) {
00666      dmx_pes_filter_params pesFilterParams;
00667      memset(&pesFilterParams, 0, sizeof(pesFilterParams));
00668      if (On) {
00669         if (Handle->handle < 0) {
00670            Handle->handle = DvbOpen(DEV_DVB_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
00671            if (Handle->handle < 0) {
00672               LOG_ERROR;
00673               return false;
00674               }
00675            }
00676         pesFilterParams.pid     = Handle->pid;
00677         pesFilterParams.input   = DMX_IN_FRONTEND;
00678         pesFilterParams.output  = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP;
00679         pesFilterParams.pes_type= PesTypes[Type < ptOther ? Type : ptOther];
00680         pesFilterParams.flags   = DMX_IMMEDIATE_START;
00681         if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
00682            LOG_ERROR;
00683            return false;
00684            }
00685         }
00686      else if (!Handle->used) {
00687         CHECK(ioctl(Handle->handle, DMX_STOP));
00688         if (Type <= ptTeletext) {
00689            pesFilterParams.pid     = 0x1FFF;
00690            pesFilterParams.input   = DMX_IN_FRONTEND;
00691            pesFilterParams.output  = DMX_OUT_DECODER;
00692            pesFilterParams.pes_type= PesTypes[Type];
00693            pesFilterParams.flags   = DMX_IMMEDIATE_START;
00694            CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
00695            if (PesTypes[Type] == DMX_PES_VIDEO) // let's only do this once
00696               SetPlayMode(pmNone); // necessary to switch a PID from DMX_PES_VIDEO/AUDIO to DMX_PES_OTHER
00697            }
00698         close(Handle->handle);
00699         Handle->handle = -1;
00700         }
00701      }
00702   return true;
00703 }
00704 
00705 int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
00706 {
00707   const char *FileName = *cDvbName(DEV_DVB_DEMUX, CardIndex());
00708   int f = open(FileName, O_RDWR | O_NONBLOCK);
00709   if (f >= 0) {
00710      dmx_sct_filter_params sctFilterParams;
00711      memset(&sctFilterParams, 0, sizeof(sctFilterParams));
00712      sctFilterParams.pid = Pid;
00713      sctFilterParams.timeout = 0;
00714      sctFilterParams.flags = DMX_IMMEDIATE_START;
00715      sctFilterParams.filter.filter[0] = Tid;
00716      sctFilterParams.filter.mask[0] = Mask;
00717      if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
00718         return f;
00719      else {
00720         esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
00721         close(f);
00722         }
00723      }
00724   else
00725      esyslog("ERROR: can't open filter handle on '%s'", FileName);
00726   return -1;
00727 }
00728 
00729 void cDvbDevice::TurnOffLiveMode(bool LiveView)
00730 {
00731   if (LiveView) {
00732      // Avoid noise while switching:
00733      CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
00734      CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
00735      CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
00736      CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
00737      }
00738 
00739   // Turn off live PIDs:
00740 
00741   DetachAll(pidHandles[ptAudio].pid);
00742   DetachAll(pidHandles[ptVideo].pid);
00743   DetachAll(pidHandles[ptPcr].pid);
00744   DetachAll(pidHandles[ptTeletext].pid);
00745   DelPid(pidHandles[ptAudio].pid);
00746   DelPid(pidHandles[ptVideo].pid);
00747   DelPid(pidHandles[ptPcr].pid, ptPcr);
00748   DelPid(pidHandles[ptTeletext].pid);
00749   DelPid(pidHandles[ptDolby].pid);
00750 }
00751 
00752 bool cDvbDevice::ProvidesSource(int Source) const
00753 {
00754   int type = Source & cSource::st_Mask;
00755   return type == cSource::stNone
00756       || type == cSource::stCable && frontendType == FE_QAM
00757       || type == cSource::stSat   && frontendType == FE_QPSK
00758       || type == cSource::stTerr  && frontendType == FE_OFDM;
00759 }
00760 
00761 bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
00762 {
00763   return ProvidesSource(Channel->Source()) && (!cSource::IsSat(Channel->Source()) || !Setup.DiSEqC || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()));
00764 }
00765 
00766 bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
00767 {
00768   bool result = false;
00769   bool hasPriority = Priority < 0 || Priority > this->Priority();
00770   bool needsDetachReceivers = false;
00771 
00772   if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel)) {
00773      result = hasPriority;
00774      if (Priority >= 0 && Receiving(true)) {
00775         if (dvbTuner->IsTunedTo(Channel)) {
00776            if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
00777 #ifdef DO_MULTIPLE_RECORDINGS
00778 #ifndef DO_MULTIPLE_CA_CHANNELS
00779               if (Ca() >= CA_ENCRYPTED_MIN || Channel->Ca() >= CA_ENCRYPTED_MIN)
00780                  needsDetachReceivers = Ca() != Channel->Ca();
00781               else
00782 #endif
00783               if (!IsPrimaryDevice())
00784                  result = true;
00785 #ifdef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
00786               else
00787                  result = Priority >= Setup.PrimaryLimit;
00788 #endif
00789 #endif
00790               }
00791            else
00792               result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit;
00793            }
00794         else
00795            needsDetachReceivers = true;
00796         }
00797      }
00798   if (NeedsDetachReceivers)
00799      *NeedsDetachReceivers = needsDetachReceivers;
00800   return result;
00801 }
00802 
00803 bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel)
00804 {
00805   return dvbTuner->IsTunedTo(Channel);
00806 }
00807 
00808 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
00809 {
00810   bool DoTune = !dvbTuner->IsTunedTo(Channel);
00811 
00812   bool TurnOffLivePIDs = HasDecoder()
00813                          && (DoTune
00814                             || !IsPrimaryDevice()
00815                             || LiveView // for a new live view the old PIDs need to be turned off
00816                             || pidHandles[ptVideo].pid == Channel->Vpid() // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
00817                             );
00818 
00819   bool StartTransferMode = IsPrimaryDevice() && !DoTune
00820                            && (LiveView && HasPid(Channel->Vpid() ? Channel->Vpid() : Channel->Apid(0)) && (pidHandles[ptVideo].pid != Channel->Vpid() || (pidHandles[ptAudio].pid != Channel->Apid(0) && (Channel->Dpid(0) ? pidHandles[ptAudio].pid != Channel->Dpid(0) : true)))// the PID is already set as DMX_PES_OTHER
00821                               || !LiveView && (pidHandles[ptVideo].pid == Channel->Vpid() || pidHandles[ptAudio].pid == Channel->Apid(0)) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
00822                               );
00823 
00824   bool TurnOnLivePIDs = HasDecoder() && !StartTransferMode && LiveView;
00825 
00826 #ifndef DO_MULTIPLE_RECORDINGS
00827   TurnOffLivePIDs = TurnOnLivePIDs = true;
00828   StartTransferMode = false;
00829 #endif
00830 
00831   // Turn off live PIDs if necessary:
00832 
00833   if (TurnOffLivePIDs)
00834      TurnOffLiveMode(LiveView);
00835 
00836   // Set the tuner:
00837 
00838   dvbTuner->Set(Channel, DoTune);
00839 
00840   // If this channel switch was requested by the EITScanner we don't wait for
00841   // a lock and don't set any live PIDs (the EITScanner will wait for the lock
00842   // by itself before setting any filters):
00843 
00844   if (EITScanner.UsesDevice(this)) //XXX
00845      return true;
00846 
00847   // PID settings:
00848 
00849   if (TurnOnLivePIDs) {
00850      SetAudioBypass(false);
00851      if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(Channel->Vpid(), ptVideo) && AddPid(Channel->Apid(0), ptAudio))) {
00852         esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
00853         return false;
00854         }
00855      if (IsPrimaryDevice())
00856         AddPid(Channel->Tpid(), ptTeletext);
00857      CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schlüßler <marco@lordzodiac.de> this works
00858                                                    // to avoid missing audio after replaying a DVD; with 'false' there is an audio disturbance when switching
00859                                                    // between two channels on the same transponder on DVB-S
00860      CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
00861      }
00862   else if (StartTransferMode)
00863      cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids()));
00864 
00865   return true;
00866 }
00867 
00868 bool cDvbDevice::HasLock(int TimeoutMs)
00869 {
00870   return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
00871 }
00872 
00873 int cDvbDevice::GetAudioChannelDevice(void)
00874 {
00875   if (HasDecoder()) {
00876      audio_status_t as;
00877      CHECK(ioctl(fd_audio, AUDIO_GET_STATUS, &as));
00878      return as.channel_select;
00879      }
00880   return 0;
00881 }
00882 
00883 void cDvbDevice::SetAudioChannelDevice(int AudioChannel)
00884 {
00885   if (HasDecoder())
00886      CHECK(ioctl(fd_audio, AUDIO_CHANNEL_SELECT, AudioChannel));
00887 }
00888 
00889 void cDvbDevice::SetVolumeDevice(int Volume)
00890 {
00891   if (HasDecoder()) {
00892      if (digitalAudio)
00893         Volume = 0;
00894      audio_mixer_t am;
00895      // conversion for linear volume response:
00896      am.volume_left = am.volume_right = 2 * Volume - Volume * Volume / 255;
00897      CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
00898      }
00899 }
00900 
00901 void cDvbDevice::SetDigitalAudioDevice(bool On)
00902 {
00903   if (digitalAudio != On) {
00904      if (digitalAudio)
00905         cCondWait::SleepMs(1000); // Wait until any leftover digital data has been flushed
00906      digitalAudio = On;
00907      SetVolumeDevice(On || IsMute() ? 0 : CurrentVolume());
00908      }
00909 }
00910 
00911 void cDvbDevice::SetTransferModeForDolbyDigital(int Mode)
00912 {
00913   setTransferModeForDolbyDigital = Mode;
00914 }
00915 
00916 void cDvbDevice::SetAudioTrackDevice(eTrackType Type)
00917 {
00918   const tTrackId *TrackId = GetTrack(Type);
00919   if (TrackId && TrackId->id) {
00920      SetAudioBypass(false);
00921      if (IS_AUDIO_TRACK(Type) || (IS_DOLBY_TRACK(Type) && SetAudioBypass(true))) {
00922         if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) {
00923            DetachAll(pidHandles[ptAudio].pid);
00924            if (ciHandler)
00925               ciHandler->SetPid(pidHandles[ptAudio].pid, false);
00926            pidHandles[ptAudio].pid = TrackId->id;
00927            SetPid(&pidHandles[ptAudio], ptAudio, true);
00928            if (ciHandler) {
00929               ciHandler->SetPid(pidHandles[ptAudio].pid, true);
00930               ciHandler->StartDecrypting();
00931               }
00932            }
00933         }
00934      else if (IS_DOLBY_TRACK(Type)) {
00935         if (setTransferModeForDolbyDigital == 0)
00936            return;
00937         // Currently this works only in Transfer Mode
00938         ForceTransferMode();
00939         }
00940      }
00941 }
00942 
00943 bool cDvbDevice::CanReplay(void) const
00944 {
00945 #ifndef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
00946   if (Receiving())
00947      return false;
00948 #endif
00949   return cDevice::CanReplay();
00950 }
00951 
00952 bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
00953 {
00954   if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) {
00955      // reopen the devices
00956      fd_video = DvbOpen(DEV_DVB_VIDEO,  CardIndex(), O_RDWR | O_NONBLOCK);
00957      fd_audio = DvbOpen(DEV_DVB_AUDIO,  CardIndex(), O_RDWR | O_NONBLOCK);
00958      SetVideoFormat(Setup.VideoFormat);
00959      }
00960 
00961   switch (PlayMode) {
00962     case pmNone:
00963          // special handling to return from PCM replay:
00964          CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
00965          CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
00966          CHECK(ioctl(fd_video, VIDEO_PLAY));
00967 
00968          CHECK(ioctl(fd_video, VIDEO_STOP, true));
00969          CHECK(ioctl(fd_audio, AUDIO_STOP, true));
00970          CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
00971          CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
00972          CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
00973          CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
00974          CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
00975          CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
00976          break;
00977     case pmAudioVideo:
00978     case pmAudioOnlyBlack:
00979          if (playMode == pmNone)
00980             TurnOffLiveMode(true);
00981          CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
00982          CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
00983          CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo));
00984          CHECK(ioctl(fd_audio, AUDIO_PLAY));
00985          CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
00986          CHECK(ioctl(fd_video, VIDEO_PLAY));
00987          break;
00988     case pmAudioOnly:
00989          CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
00990          CHECK(ioctl(fd_audio, AUDIO_STOP, true));
00991          CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
00992          CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
00993          CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
00994          CHECK(ioctl(fd_audio, AUDIO_PLAY));
00995          CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
00996          break;
00997     case pmVideoOnly:
00998          CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
00999          CHECK(ioctl(fd_video, VIDEO_STOP, true));
01000          CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
01001          CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
01002          CHECK(ioctl(fd_audio, AUDIO_PLAY));
01003          CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
01004          CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
01005          CHECK(ioctl(fd_video, VIDEO_PLAY));
01006          break;
01007     case pmExtern_THIS_SHOULD_BE_AVOIDED:
01008          close(fd_video);
01009          close(fd_audio);
01010          fd_video = fd_audio = -1;
01011          break;
01012     }
01013   playMode = PlayMode;
01014   return true;
01015 }
01016 
01017 int64_t cDvbDevice::GetSTC(void)
01018 {
01019   if (fd_stc >= 0) {
01020      struct dmx_stc stc;
01021      stc.num = 0;
01022      if (ioctl(fd_stc, DMX_GET_STC, &stc) == -1) {
01023         esyslog("ERROR: stc %d: %m", CardIndex() + 1);
01024         return -1;
01025         }
01026      return stc.stc / stc.base;
01027      }
01028   return -1;
01029 }
01030 
01031 void cDvbDevice::TrickSpeed(int Speed)
01032 {
01033   if (fd_video >= 0)
01034      CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
01035 }
01036 
01037 void cDvbDevice::Clear(void)
01038 {
01039   if (fd_video >= 0)
01040      CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
01041   if (fd_audio >= 0)
01042      CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
01043   cDevice::Clear();
01044 }
01045 
01046 void cDvbDevice::Play(void)
01047 {
01048   if (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) {
01049      if (fd_audio >= 0)
01050         CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
01051      }
01052   else {
01053      if (fd_audio >= 0)
01054         CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
01055      if (fd_video >= 0)
01056         CHECK(ioctl(fd_video, VIDEO_CONTINUE));
01057      }
01058   cDevice::Play();
01059 }
01060 
01061 void cDvbDevice::Freeze(void)
01062 {
01063   if (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) {
01064      if (fd_audio >= 0)
01065         CHECK(ioctl(fd_audio, AUDIO_PAUSE));
01066      }
01067   else {
01068      if (fd_audio >= 0)
01069         CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
01070      if (fd_video >= 0)
01071         CHECK(ioctl(fd_video, VIDEO_FREEZE));
01072      }
01073   cDevice::Freeze();
01074 }
01075 
01076 void cDvbDevice::Mute(void)
01077 {
01078   if (fd_audio >= 0) {
01079      CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
01080      CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
01081      }
01082   cDevice::Mute();
01083 }
01084 
01085 void cDvbDevice::StillPicture(const uchar *Data, int Length)
01086 {
01087   if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) {
01088      // PES data
01089      char *buf = MALLOC(char, Length);
01090      if (!buf)
01091         return;
01092      int i = 0;
01093      int blen = 0;
01094      while (i < Length - 6) {
01095            if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
01096               int len = Data[i + 4] * 256 + Data[i + 5];
01097               if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet
01098                  // skip PES header
01099                  int offs = i + 6;
01100                  // skip header extension
01101                  if ((Data[i + 6] & 0xC0) == 0x80) {
01102                     // MPEG-2 PES header
01103                     if (Data[i + 8] >= Length)
01104                        break;
01105                     offs += 3;
01106                     offs += Data[i + 8];
01107                     len -= 3;
01108                     len -= Data[i + 8];
01109                     if (len < 0 || offs + len > Length)
01110                        break;
01111                     }
01112                  else {
01113                     // MPEG-1 PES header
01114                     while (offs < Length && len > 0 && Data[offs] == 0xFF) {
01115                           offs++;
01116                           len--;
01117                           }
01118                     if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) {
01119                        offs += 2;
01120                        len -= 2;
01121                        }
01122                     if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) {
01123                        offs += 5;
01124                        len -= 5;
01125                        }
01126                     else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) {
01127                        offs += 10;
01128                        len -= 10;
01129                        }
01130                     else if (offs < Length && len > 0) {
01131                        offs++;
01132                        len--;
01133                        }
01134                     }
01135                  if (blen + len > Length) // invalid PES length field
01136                     break;
01137                  memcpy(&buf[blen], &Data[offs], len);
01138                  i = offs + len;
01139                  blen += len;
01140                  }
01141               else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets
01142                  i += len + 6;
01143               else
01144                  i++;
01145               }
01146            else
01147               i++;
01148            }
01149      video_still_picture sp = { buf, blen };
01150      CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
01151      free(buf);
01152      }
01153   else {
01154      // non-PES data
01155      video_still_picture sp = { (char *)Data, Length };
01156      CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
01157      }
01158 }
01159 
01160 bool cDvbDevice::Poll(cPoller &Poller, int TimeoutMs)
01161 {
01162   Poller.Add((playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video, true);
01163   return Poller.Poll(TimeoutMs);
01164 }
01165 
01166 bool cDvbDevice::Flush(int TimeoutMs)
01167 {
01168   //TODO actually this function should wait until all buffered data has been processed by the card, but how?
01169   return true;
01170 }
01171 
01172 int cDvbDevice::PlayVideo(const uchar *Data, int Length)
01173 {
01174   return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
01175 }
01176 
01177 int cDvbDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
01178 {
01179   return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
01180 }
01181 
01182 bool cDvbDevice::OpenDvr(void)
01183 {
01184   CloseDvr();
01185   fd_dvr = DvbOpen(DEV_DVB_DVR, CardIndex(), O_RDONLY | O_NONBLOCK, true);
01186   if (fd_dvr >= 0)
01187      tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1);
01188   return fd_dvr >= 0;
01189 }
01190 
01191 void cDvbDevice::CloseDvr(void)
01192 {
01193   if (fd_dvr >= 0) {
01194      delete tsBuffer;
01195      tsBuffer = NULL;
01196      close(fd_dvr);
01197      fd_dvr = -1;
01198      }
01199 }
01200 
01201 bool cDvbDevice::GetTSPacket(uchar *&Data)
01202 {
01203   if (tsBuffer) {
01204      Data = tsBuffer->Get();
01205      return true;
01206      }
01207   return false;
01208 }

Generated on Tue Nov 6 19:57:52 2007 for VDR by  doxygen 1.5.3-20071008