vdr  1.7.27
dvbhdffdevice.c
Go to the documentation of this file.
00001 /*
00002  * dvbhdffdevice.c: The DVB HD Full Featured device interface
00003  *
00004  * See the README file for copyright information and how to reach the author.
00005  *
00006  * $Id: dvbhdffdevice.c 1.41 2012/03/07 13:52:41 kls Exp $
00007  */
00008 
00009 #include <stdint.h>
00010 
00011 #include "dvbhdffdevice.h"
00012 #include <errno.h>
00013 #include <limits.h>
00014 #include <libsi/si.h>
00015 #include <linux/videodev2.h>
00016 #include <linux/dvb/audio.h>
00017 #include <linux/dvb/dmx.h>
00018 #include <linux/dvb/video.h>
00019 #include <sys/ioctl.h>
00020 #include <sys/mman.h>
00021 #include <vdr/eitscan.h>
00022 #include <vdr/transfer.h>
00023 #include "hdffosd.h"
00024 #include "setup.h"
00025 
00026 // --- cDvbHdFfDevice ----------------------------------------------------------
00027 
00028 int cDvbHdFfDevice::devHdffOffset = -1;
00029 
00030 cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend)
00031 :cDvbDevice(Adapter, Frontend)
00032 {
00033   spuDecoder = NULL;
00034   audioChannel = 0;
00035   playMode = pmNone;
00036   mHdffCmdIf = NULL;
00037 
00038   // Devices that are only present on cards with decoders:
00039 
00040   fd_osd      = DvbOpen(DEV_DVB_OSD,    adapter, frontend, O_RDWR);
00041   fd_video    = DvbOpen(DEV_DVB_VIDEO,  adapter, frontend, O_RDWR | O_NONBLOCK);
00042   fd_audio    = DvbOpen(DEV_DVB_AUDIO,  adapter, frontend, O_RDWR | O_NONBLOCK);
00043 
00044   //TODO missing /dev/video offset calculation
00045 
00046   isHdffPrimary = false;
00047   if (devHdffOffset < 0) {
00048      devHdffOffset = adapter;
00049      isHdffPrimary = true;
00050      mHdffCmdIf = new HDFF::cHdffCmdIf(fd_osd);
00051 
00052      /* reset some stuff in case the VDR was killed before and had no chance
00053         to clean up. */
00054      mHdffCmdIf->CmdOsdReset();
00055 
00056      mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
00057      mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
00058 
00059      mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
00060      mHdffCmdIf->CmdAvSetPcrPid(0, 0);
00061      mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
00062      mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
00063 
00064      ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
00065      mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
00066      mHdffCmdIf->CmdAvEnableSync(0, true);
00067      mHdffCmdIf->CmdAvSetPlayMode(0, true);
00068      /* reset done */
00069 
00070      mHdffCmdIf->CmdAvSetAudioDelay(gHdffSetup.AudioDelay);
00071      mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) gHdffSetup.AudioDownmix);
00072      mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) gHdffSetup.AnalogueVideo);
00073      mHdffCmdIf->CmdHdmiSetVideoMode(gHdffSetup.GetVideoMode());
00074 
00075      HdffHdmiConfig_t hdmiConfig;
00076      memset(&hdmiConfig, 0, sizeof(hdmiConfig));
00077      hdmiConfig.TransmitAudio = true;
00078      hdmiConfig.ForceDviMode = false;
00079      hdmiConfig.CecEnabled = gHdffSetup.CecEnabled;
00080      strcpy(hdmiConfig.CecDeviceName, "VDR");
00081      hdmiConfig.VideoModeAdaption = (HdffVideoModeAdaption_t) gHdffSetup.VideoModeAdaption;
00082      mHdffCmdIf->CmdHdmiConfigure(&hdmiConfig);
00083 
00084      mHdffCmdIf->CmdRemoteSetProtocol((HdffRemoteProtocol_t) gHdffSetup.RemoteProtocol);
00085      mHdffCmdIf->CmdRemoteSetAddressFilter(gHdffSetup.RemoteAddress >= 0, gHdffSetup.RemoteAddress);
00086      }
00087 }
00088 
00089 cDvbHdFfDevice::~cDvbHdFfDevice()
00090 {
00091     delete spuDecoder;
00092     if (isHdffPrimary)
00093     {
00094         if (gHdffSetup.CecEnabled && gHdffSetup.CecTvOff)
00095         {
00096             mHdffCmdIf->CmdHdmiSendCecCommand(HDFF_CEC_COMMAND_TV_OFF);
00097         }
00098         delete mHdffCmdIf;
00099     }
00100     // We're not explicitly closing any device files here, since this sometimes
00101     // caused segfaults. Besides, the program is about to terminate anyway...
00102 }
00103 
00104 void cDvbHdFfDevice::MakePrimaryDevice(bool On)
00105 {
00106   if (On)
00107      new cHdffOsdProvider(mHdffCmdIf);
00108   cDvbDevice::MakePrimaryDevice(On);
00109 }
00110 
00111 bool cDvbHdFfDevice::HasDecoder(void) const
00112 {
00113   return isHdffPrimary;
00114 }
00115 
00116 cSpuDecoder *cDvbHdFfDevice::GetSpuDecoder(void)
00117 {
00118   if (!spuDecoder && IsPrimaryDevice())
00119      spuDecoder = new cDvbSpuDecoder();
00120   return spuDecoder;
00121 }
00122 
00123 uchar *cDvbHdFfDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
00124 {
00125   //TODO
00126   return NULL;
00127 }
00128 
00129 void cDvbHdFfDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
00130 {
00131   //TODO???
00132   cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
00133 }
00134 
00135 void cDvbHdFfDevice::SetVideoFormat(bool VideoFormat16_9)
00136 {
00137   HdffVideoFormat_t videoFormat;
00138   videoFormat.AutomaticEnabled = true;
00139   videoFormat.AfdEnabled = true;
00140   videoFormat.TvFormat = (HdffTvFormat_t) gHdffSetup.TvFormat;
00141   videoFormat.VideoConversion = (HdffVideoConversion_t) gHdffSetup.VideoConversion;
00142   mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
00143 }
00144 
00145 eVideoSystem cDvbHdFfDevice::GetVideoSystem(void)
00146 {
00147   eVideoSystem VideoSystem = vsPAL;
00148   if (fd_video >= 0) {
00149      video_size_t vs;
00150      if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
00151         if (vs.h == 480 || vs.h == 240)
00152            VideoSystem = vsNTSC;
00153         }
00154      else
00155         LOG_ERROR;
00156      }
00157   return VideoSystem;
00158 }
00159 
00160 void cDvbHdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
00161 {
00162   if (fd_video >= 0) {
00163      video_size_t vs;
00164      if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) {
00165         Width = vs.w;
00166         Height = vs.h;
00167         switch (vs.aspect_ratio) {
00168           default:
00169           case VIDEO_FORMAT_4_3:   VideoAspect =  4.0 / 3.0; break;
00170           case VIDEO_FORMAT_16_9:  VideoAspect = 16.0 / 9.0; break;
00171           case VIDEO_FORMAT_221_1: VideoAspect =       2.21; break;
00172           }
00173         return;
00174         }
00175      else
00176         LOG_ERROR;
00177      }
00178   cDevice::GetVideoSize(Width, Height, VideoAspect);
00179 }
00180 
00181 void cDvbHdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
00182 {
00183   gHdffSetup.GetOsdSize(Width, Height, PixelAspect);
00184 }
00185 
00186 /*TODO obsolete?
00187 bool cDvbHdFfDevice::SetAudioBypass(bool On)
00188 {
00189   if (setTransferModeForDolbyDigital != 1)
00190      return false;
00191   return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
00192 }
00193 TODO*/
00194 
00195 bool cDvbHdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On)
00196 {
00197   if (Handle->pid) {
00198      dmx_pes_filter_params pesFilterParams;
00199      memset(&pesFilterParams, 0, sizeof(pesFilterParams));
00200      if (On) {
00201         if (Handle->handle < 0) {
00202            Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
00203            if (Handle->handle < 0) {
00204               LOG_ERROR;
00205               return false;
00206               }
00207            }
00208         if (Type == ptPcr)
00209            mHdffCmdIf->CmdAvSetPcrPid(0, Handle->pid);
00210         else if (Type == ptVideo) {
00211            if (Handle->streamType == 0x1B)
00212               mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_H264);
00213            else
00214               mHdffCmdIf->CmdAvSetVideoPid(0, Handle->pid, HDFF_VIDEO_STREAM_MPEG2);
00215            }
00216         else if (Type == ptAudio)
00217            mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_MPEG1);
00218         else if (Type == ptDolby)
00219            mHdffCmdIf->CmdAvSetAudioPid(0, Handle->pid, HDFF_AUDIO_STREAM_AC3);
00220         if (!(Type <= ptDolby && Handle->used <= 1)) {
00221            pesFilterParams.pid     = Handle->pid;
00222            pesFilterParams.input   = DMX_IN_FRONTEND;
00223            pesFilterParams.output  = DMX_OUT_TS_TAP;
00224            pesFilterParams.pes_type= DMX_PES_OTHER;
00225            pesFilterParams.flags   = DMX_IMMEDIATE_START;
00226            if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
00227               LOG_ERROR;
00228               return false;
00229               }
00230            }
00231         }
00232      else if (!Handle->used) {
00233         CHECK(ioctl(Handle->handle, DMX_STOP));
00234         if (Type == ptPcr)
00235            mHdffCmdIf->CmdAvSetPcrPid(0, 0);
00236         else if (Type == ptVideo)
00237            mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
00238         else if (Type == ptAudio)
00239            mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
00240         else if (Type == ptDolby)
00241            mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_AC3);
00242         //TODO missing setting to 0x1FFF??? see cDvbDevice::SetPid()
00243         close(Handle->handle);
00244         Handle->handle = -1;
00245         }
00246      }
00247   return true;
00248 }
00249 
00250 void cDvbHdFfDevice::TurnOffLiveMode(bool LiveView)
00251 {
00252   // Turn off live PIDs:
00253 
00254   DetachAll(pidHandles[ptAudio].pid);
00255   DetachAll(pidHandles[ptVideo].pid);
00256   DetachAll(pidHandles[ptPcr].pid);
00257   DetachAll(pidHandles[ptTeletext].pid);
00258   DelPid(pidHandles[ptAudio].pid);
00259   DelPid(pidHandles[ptVideo].pid);
00260   DelPid(pidHandles[ptPcr].pid, ptPcr);
00261   DelPid(pidHandles[ptTeletext].pid);
00262   DelPid(pidHandles[ptDolby].pid);
00263 }
00264 
00265 bool cDvbHdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
00266 {
00267   int apid = Channel->Apid(0);
00268   int vpid = Channel->Vpid();
00269   int dpid = Channel->Dpid(0);
00270 
00271   bool DoTune = !IsTunedToTransponder(Channel);
00272 
00273   bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid;
00274   bool pidHandlesAudio = pidHandles[ptAudio].pid == apid;
00275 
00276   bool TurnOffLivePIDs = DoTune
00277                          || !IsPrimaryDevice()
00278                          || LiveView // for a new live view the old PIDs need to be turned off
00279                          || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
00280                          ;
00281 
00282   bool StartTransferMode = IsPrimaryDevice() && !DoTune
00283                            && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER
00284                               || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER
00285                               );
00286   if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber()))
00287      StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN;
00288 
00289   bool TurnOnLivePIDs = !StartTransferMode && LiveView;
00290 
00291   // Turn off live PIDs if necessary:
00292 
00293   if (TurnOffLivePIDs)
00294      TurnOffLiveMode(LiveView);
00295 
00296   // Set the tuner:
00297 
00298   if (!cDvbDevice::SetChannelDevice(Channel, LiveView))
00299      return false;
00300 
00301   // PID settings:
00302 
00303   if (TurnOnLivePIDs) {
00304      //SetAudioBypass(false);//TODO obsolete?
00305      if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid, ptAudio))) {
00306         esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
00307         return false;
00308         }
00309      if (IsPrimaryDevice())
00310         AddPid(Channel->Tpid(), ptTeletext);//TODO obsolete?
00311      }
00312   else if (StartTransferMode)
00313      cControl::Launch(new cTransferControl(this, Channel));
00314 
00315   return true;
00316 }
00317 
00318 int cDvbHdFfDevice::GetAudioChannelDevice(void)
00319 {
00320   return audioChannel;
00321 }
00322 
00323 void cDvbHdFfDevice::SetAudioChannelDevice(int AudioChannel)
00324 {
00325   mHdffCmdIf->CmdAvSetAudioChannel(AudioChannel);
00326   audioChannel = AudioChannel;
00327 }
00328 
00329 void cDvbHdFfDevice::SetVolumeDevice(int Volume)
00330 {
00331   mHdffCmdIf->CmdMuxSetVolume(Volume * 100 / 255);
00332 }
00333 
00334 void cDvbHdFfDevice::SetDigitalAudioDevice(bool On)
00335 {
00336   // not needed
00337 }
00338 
00339 void cDvbHdFfDevice::SetAudioTrackDevice(eTrackType Type)
00340 {
00341   //printf("SetAudioTrackDevice %d\n", Type);
00342   const tTrackId *TrackId = GetTrack(Type);
00343   if (TrackId && TrackId->id) {
00344      if (IS_AUDIO_TRACK(Type)) {
00345         if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) {
00346            DetachAll(pidHandles[ptAudio].pid);
00347            if (CamSlot())
00348               CamSlot()->SetPid(pidHandles[ptAudio].pid, false);
00349            pidHandles[ptAudio].pid = TrackId->id;
00350            SetPid(&pidHandles[ptAudio], ptAudio, true);
00351            if (CamSlot()) {
00352               CamSlot()->SetPid(pidHandles[ptAudio].pid, true);
00353               CamSlot()->StartDecrypting();
00354               }
00355            }
00356         }
00357      else if (IS_DOLBY_TRACK(Type)) {
00358         pidHandles[ptDolby].pid = TrackId->id;
00359         SetPid(&pidHandles[ptDolby], ptDolby, true);
00360         }
00361      }
00362 }
00363 
00364 bool cDvbHdFfDevice::CanReplay(void) const
00365 {
00366   return cDevice::CanReplay();
00367 }
00368 
00369 bool cDvbHdFfDevice::SetPlayMode(ePlayMode PlayMode)
00370 {
00371   if (PlayMode == pmNone) {
00372      mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
00373      mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
00374 
00375      mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
00376      mHdffCmdIf->CmdAvSetPcrPid(0, 0);
00377      mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
00378      mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
00379 
00380      ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
00381      mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
00382      mHdffCmdIf->CmdAvEnableSync(0, true);
00383      mHdffCmdIf->CmdAvSetPlayMode(0, true);
00384      }
00385   else {
00386      if (playMode == pmNone)
00387         TurnOffLiveMode(true);
00388 
00389      mHdffCmdIf->CmdAvSetPlayMode(1, Transferring() || (cTransferControl::ReceiverDevice() == this));
00390      mHdffCmdIf->CmdAvSetStc(0, 100000);
00391      mHdffCmdIf->CmdAvEnableSync(0, true);
00392      mHdffCmdIf->CmdAvEnableVideoAfterStop(0, true);
00393 
00394      playVideoPid = -1;
00395      playAudioPid = -1;
00396      audioCounter = 0;
00397      videoCounter = 0;
00398      freezed = false;
00399      trickMode = false;
00400 
00401      mHdffCmdIf->CmdAvSetDecoderInput(0, 2);
00402      ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
00403      }
00404   playMode = PlayMode;
00405   return true;
00406 }
00407 
00408 int64_t cDvbHdFfDevice::GetSTC(void)
00409 {
00410   if (fd_video >= 0) {
00411      uint64_t pts;
00412      if (ioctl(fd_video, VIDEO_GET_PTS, &pts) == -1) {
00413         esyslog("ERROR: pts %d: %m", CardIndex() + 1);
00414         return -1;
00415         }
00416      return pts;
00417      }
00418   if (fd_audio >= 0) {
00419      uint64_t pts;
00420      if (ioctl(fd_audio, AUDIO_GET_PTS, &pts) == -1) {
00421         esyslog("ERROR: pts %d: %m", CardIndex() + 1);
00422         return -1;
00423         }
00424      return pts;
00425      }
00426   return -1;
00427 }
00428 
00429 void cDvbHdFfDevice::TrickSpeed(int Speed)
00430 {
00431   freezed = false;
00432   mHdffCmdIf->CmdAvEnableSync(0, false);
00433   mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
00434   playAudioPid = -1;
00435   if (Speed > 0)
00436      mHdffCmdIf->CmdAvSetVideoSpeed(0, 100 / Speed);
00437   trickMode = true;
00438 }
00439 
00440 void cDvbHdFfDevice::Clear(void)
00441 {
00442   CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
00443   mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
00444   mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
00445   playVideoPid = -1;
00446   playAudioPid = -1;
00447   cDevice::Clear();
00448 }
00449 
00450 void cDvbHdFfDevice::Play(void)
00451 {
00452   freezed = false;
00453   trickMode = false;
00454   mHdffCmdIf->CmdAvEnableSync(0, true);
00455   mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
00456   mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
00457   cDevice::Play();
00458 }
00459 
00460 void cDvbHdFfDevice::Freeze(void)
00461 {
00462   freezed = true;
00463   mHdffCmdIf->CmdAvSetVideoSpeed(0, 0);
00464   mHdffCmdIf->CmdAvSetAudioSpeed(0, 0);
00465   cDevice::Freeze();
00466 }
00467 
00468 void cDvbHdFfDevice::Mute(void)
00469 {
00470   //TODO???
00471   cDevice::Mute();
00472 }
00473 
00474 static HdffVideoStreamType_t MapVideoStreamTypes(int Vtype)
00475 {
00476   switch (Vtype) {
00477     case 0x01: return HDFF_VIDEO_STREAM_MPEG1;
00478     case 0x02: return HDFF_VIDEO_STREAM_MPEG2;
00479     case 0x1B: return HDFF_VIDEO_STREAM_H264;
00480     default: return HDFF_VIDEO_STREAM_MPEG2; // fallback to MPEG2
00481     }
00482 }
00483 
00484 void cDvbHdFfDevice::StillPicture(const uchar *Data, int Length)
00485 {
00486   if (!Data || Length < TS_SIZE)
00487      return;
00488   if (Data[0] == 0x47) {
00489      // TS data
00490      cDevice::StillPicture(Data, Length);
00491      }
00492   else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) {
00493      // PES data
00494      char *buf = MALLOC(char, Length);
00495      if (!buf)
00496         return;
00497      int i = 0;
00498      int blen = 0;
00499      while (i < Length - 6) {
00500            if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
00501               int len = Data[i + 4] * 256 + Data[i + 5];
00502               if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet
00503                  // skip PES header
00504                  int offs = i + 6;
00505                  // skip header extension
00506                  if ((Data[i + 6] & 0xC0) == 0x80) {
00507                     // MPEG-2 PES header
00508                     if (Data[i + 8] >= Length)
00509                        break;
00510                     offs += 3;
00511                     offs += Data[i + 8];
00512                     len -= 3;
00513                     len -= Data[i + 8];
00514                     if (len < 0 || offs + len > Length)
00515                        break;
00516                     }
00517                  else {
00518                     // MPEG-1 PES header
00519                     while (offs < Length && len > 0 && Data[offs] == 0xFF) {
00520                           offs++;
00521                           len--;
00522                           }
00523                     if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) {
00524                        offs += 2;
00525                        len -= 2;
00526                        }
00527                     if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) {
00528                        offs += 5;
00529                        len -= 5;
00530                        }
00531                     else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) {
00532                        offs += 10;
00533                        len -= 10;
00534                        }
00535                     else if (offs < Length && len > 0) {
00536                        offs++;
00537                        len--;
00538                        }
00539                     }
00540                  if (blen + len > Length) // invalid PES length field
00541                     break;
00542                  memcpy(&buf[blen], &Data[offs], len);
00543                  i = offs + len;
00544                  blen += len;
00545                  }
00546               else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets
00547                  i += len + 6;
00548               else
00549                  i++;
00550               }
00551            else
00552               i++;
00553            }
00554      mHdffCmdIf->CmdAvShowStillImage(0, (uint8_t *)buf, blen, MapVideoStreamTypes(PatPmtParser()->Vtype()));
00555      free(buf);
00556      }
00557   else {
00558      // non-PES data
00559      mHdffCmdIf->CmdAvShowStillImage(0, Data, Length, MapVideoStreamTypes(PatPmtParser()->Vtype()));
00560      }
00561 }
00562 
00563 bool cDvbHdFfDevice::Poll(cPoller &Poller, int TimeoutMs)
00564 {
00565   Poller.Add(fd_video, true);
00566   return Poller.Poll(TimeoutMs);
00567 }
00568 
00569 bool cDvbHdFfDevice::Flush(int TimeoutMs)
00570 {
00571   //TODO actually this function should wait until all buffered data has been processed by the card, but how?
00572   return true;
00573 }
00574 
00575 void cDvbHdFfDevice::BuildTsPacket(uint8_t * TsBuffer, bool PusiSet, uint16_t Pid, uint8_t Counter, const uint8_t * Data, uint32_t Length)
00576 {
00577     TsBuffer[0] = 0x47;
00578     TsBuffer[1] = PusiSet ? 0x40 : 0x00;
00579     TsBuffer[1] |= Pid >> 8;
00580     TsBuffer[2] = Pid & 0xFF;
00581     if (Length >= 184)
00582     {
00583         TsBuffer[3] = 0x10 | Counter;
00584         memcpy(TsBuffer + 4, Data, 184);
00585     }
00586     else
00587     {
00588         uint8_t adaptationLength;
00589 
00590         TsBuffer[3] = 0x30 | Counter;
00591         adaptationLength = 183 - Length;
00592         TsBuffer[4] = adaptationLength;
00593         if (adaptationLength > 0)
00594         {
00595             TsBuffer[5] = 0x00;
00596             memset(TsBuffer + 6, 0xFF, adaptationLength - 1);
00597         }
00598         memcpy(TsBuffer + 5 + adaptationLength, Data, Length);
00599     }
00600 }
00601 
00602 uint32_t cDvbHdFfDevice::PesToTs(uint8_t * TsBuffer, uint16_t Pid, uint8_t & Counter, const uint8_t * Data, uint32_t Length)
00603 {
00604     uint32_t tsOffset;
00605     uint32_t i;
00606 
00607     tsOffset = 0;
00608     i = 0;
00609     while (Length > 0)
00610     {
00611         BuildTsPacket(TsBuffer + tsOffset, i == 0, Pid, Counter, Data + i * 184, Length);
00612         if (Length >= 184)
00613             Length -= 184;
00614         else
00615             Length = 0;
00616         Counter = (Counter + 1) & 15;
00617         tsOffset += 188;
00618         i++;
00619     }
00620     return tsOffset;
00621 }
00622 
00623 int cDvbHdFfDevice::PlayVideo(const uchar *Data, int Length)
00624 {
00625     if (freezed)
00626         return -1;
00627     //TODO: support greater Length
00628     uint8_t tsBuffer[188 * 16];
00629     uint32_t tsLength;
00630     int pid = 100;
00631 
00632     tsLength = PesToTs(tsBuffer, pid, videoCounter, Data, Length);
00633 
00634     if (pid != playVideoPid) {
00635         playVideoPid = pid;
00636         mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, HDFF_VIDEO_STREAM_MPEG2, true);
00637     }
00638     if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
00639         Length = 0;
00640     return Length;
00641 }
00642 
00643 int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
00644 {
00645     if (freezed)
00646         return -1;
00647     if (trickMode)
00648         return Length;
00649     uint8_t streamId;
00650     uint8_t tsBuffer[188 * 16];
00651     uint32_t tsLength;
00652     HdffAudioStreamType_t streamType = HDFF_AUDIO_STREAM_MPEG1;
00653     HdffAvContainerType_t containerType = HDFF_AV_CONTAINER_PES;
00654     int pid;
00655 
00656     streamId = Data[3];
00657     if (streamId >= 0xC0 && streamId <= 0xDF)
00658     {
00659         streamType = HDFF_AUDIO_STREAM_MPEG1;
00660     }
00661     else if (streamId == 0xBD)
00662     {
00663         const uint8_t * payload = Data + 9 + Data[8];
00664         if ((payload[0] & 0xF8) == 0xA0)
00665         {
00666             containerType = HDFF_AV_CONTAINER_PES_DVD;
00667             streamType = HDFF_AUDIO_STREAM_PCM;
00668         }
00669         else if ((payload[0] & 0xF8) == 0x88)
00670         {
00671             containerType = HDFF_AV_CONTAINER_PES_DVD;
00672             streamType = HDFF_AUDIO_STREAM_DTS;
00673         }
00674         else if ((payload[0] & 0xF8) == 0x80)
00675         {
00676             containerType = HDFF_AV_CONTAINER_PES_DVD;
00677             streamType = HDFF_AUDIO_STREAM_AC3;
00678         }
00679         else
00680         {
00681             streamType = HDFF_AUDIO_STREAM_AC3;
00682         }
00683     }
00684     pid = 200 + (int) streamType;
00685     tsLength = PesToTs(tsBuffer, pid, audioCounter, Data, Length);
00686 
00687     if (pid != playAudioPid) {
00688         playAudioPid = pid;
00689         mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, streamType, containerType);
00690     }
00691     if (WriteAllOrNothing(fd_video, tsBuffer, tsLength, 1000, 10) <= 0)
00692         Length = 0;
00693     return Length;
00694 }
00695 
00696 int cDvbHdFfDevice::PlayTsVideo(const uchar *Data, int Length)
00697 {
00698   if (freezed)
00699     return -1;
00700   int pid = TsPid(Data);
00701   if (pid != playVideoPid) {
00702      PatPmtParser();
00703      if (pid == PatPmtParser()->Vpid()) {
00704         playVideoPid = pid;
00705         mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, MapVideoStreamTypes(PatPmtParser()->Vtype()), true);
00706         }
00707      }
00708   return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
00709 }
00710 
00711 static HdffAudioStreamType_t MapAudioStreamTypes(int Atype)
00712 {
00713   switch (Atype) {
00714     case 0x03: return HDFF_AUDIO_STREAM_MPEG1;
00715     case 0x04: return HDFF_AUDIO_STREAM_MPEG2;
00716     case SI::AC3DescriptorTag: return HDFF_AUDIO_STREAM_AC3;
00717     case SI::EnhancedAC3DescriptorTag: return HDFF_AUDIO_STREAM_EAC3;
00718     case 0x0F: return HDFF_AUDIO_STREAM_AAC;
00719     case 0x11: return HDFF_AUDIO_STREAM_HE_AAC;
00720     default: return HDFF_AUDIO_STREAM_MPEG1;
00721     }
00722 }
00723 
00724 int cDvbHdFfDevice::PlayTsAudio(const uchar *Data, int Length)
00725 {
00726   if (freezed)
00727     return -1;
00728   if (trickMode)
00729     return Length;
00730   int pid = TsPid(Data);
00731   if (pid != playAudioPid) {
00732      playAudioPid = pid;
00733      int AudioStreamType = -1;
00734      for (int i = 0; PatPmtParser()->Apid(i); i++) {
00735          if (playAudioPid == PatPmtParser()->Apid(i)) {
00736             AudioStreamType = PatPmtParser()->Atype(i);
00737             break;
00738             }
00739          }
00740      if (AudioStreamType < 0) {
00741         for (int i = 0; PatPmtParser()->Dpid(i); i++) {
00742             if (playAudioPid == PatPmtParser()->Dpid(i)) {
00743                AudioStreamType = PatPmtParser()->Dtype(i);
00744                break;
00745                }
00746             }
00747         }
00748      mHdffCmdIf->CmdAvSetAudioPid(0, playAudioPid, MapAudioStreamTypes(AudioStreamType));
00749      }
00750   return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
00751 }
00752 
00753 HDFF::cHdffCmdIf *cDvbHdFfDevice::GetHdffCmdHandler(void)
00754 {
00755   //TODO why not just keep a pointer?
00756   if (devHdffOffset >= 0) {
00757      cDvbHdFfDevice *device = (cDvbHdFfDevice *)GetDevice(devHdffOffset);
00758      if (device)
00759         return device->mHdffCmdIf;
00760      }
00761   return NULL;
00762 }
00763 
00764 // --- cDvbHdFfDeviceProbe ---------------------------------------------------
00765 
00766 bool cDvbHdFfDeviceProbe::Probe(int Adapter, int Frontend)
00767 {
00768   static uint32_t SubsystemIds[] = {
00769     0x13C23009, // Technotrend S2-6400 HDFF development samples
00770     0x13C2300A, // Technotrend S2-6400 HDFF production version
00771     0x00000000
00772     };
00773   cString FileName;
00774   cReadLine ReadLine;
00775   FILE *f = NULL;
00776   uint32_t SubsystemId = 0;
00777   FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend);
00778   if ((f = fopen(FileName, "r")) != NULL) {
00779      if (char *s = ReadLine.Read(f))
00780         SubsystemId = strtoul(s, NULL, 0) << 16;
00781      fclose(f);
00782      }
00783   FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend);
00784   if ((f = fopen(FileName, "r")) != NULL) {
00785      if (char *s = ReadLine.Read(f))
00786         SubsystemId |= strtoul(s, NULL, 0);
00787      fclose(f);
00788      }
00789   for (uint32_t *sid = SubsystemIds; *sid; sid++) {
00790       if (*sid == SubsystemId) {
00791          FileName = cString::sprintf("/dev/dvb/adapter%d/osd0", Adapter);
00792          int fd = open(FileName, O_RDWR);
00793          if (fd != -1) { //TODO treat the second path of the S2-6400 as a budget device
00794             close(fd);
00795             dsyslog("creating cDvbHdFfDevice");
00796             new cDvbHdFfDevice(Adapter, Frontend);
00797             return true;
00798             }
00799          }
00800       }
00801   return false;
00802 }