int64_t cDvbHdFfDevice::GetSTC(void) { if (isPlayingVideo) { if (fd_video >= 0) { uint64_t pts; if (ioctl(fd_video, VIDEO_GET_PTS, &pts) == -1) { esyslog("ERROR: pts %d: %m", CardIndex() + 1); return -1; } //printf("video PTS %lld\n", pts); return pts; } } else { if (fd_audio >= 0) { uint64_t pts; if (ioctl(fd_audio, AUDIO_GET_PTS, &pts) == -1) { esyslog("ERROR: pts %d: %m", CardIndex() + 1); return -1; } //printf("audio PTS %lld\n", pts); return pts; } } return -1; }
cString cSatipDevice::GetGeneralInformation(void) { //debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM); return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s", deviceIndexM, CardIndex(), pTunerM ? *pTunerM->GetInformation() : "", pTunerM ? *pTunerM->GetSignalStatus() : "", pTunerM ? *pTunerM->GetTunerStatistic() : "", *GetBufferStatistic(), *Channels.GetByNumber(cDevice::CurrentChannel())->ToText()); }
bool SCDEVICE::OpenDvr(void) { DEBUGLOG("%s", __FUNCTION__); CloseDvr(); fd_dvr = cScDevices::DvbOpen(DEV_DVB_DVR, DVB_DEV_SPEC, O_RDONLY | O_NONBLOCK, true); if (fd_dvr >= 0) { tsMutex.Lock(); tsBuffer = new DeCsaTsBuffer(fd_dvr, MEGABYTE(4), CardIndex() + 1, sCCIAdapter->GetDeCSA(), ScActive()); tsMutex.Unlock(); } return fd_dvr >= 0; }
int64_t cDvbDevice::GetSTC(void) { if (fd_stc >= 0) { struct dmx_stc stc; stc.num = 0; if (ioctl(fd_stc, DMX_GET_STC, &stc) == -1) { esyslog("ERROR: stc %d: %m", CardIndex() + 1); return -1; } return stc.stc / stc.base; } return -1; }
bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On) { if (Handle->pid) { dmx_pes_filter_params pesFilterParams; memset(&pesFilterParams, 0, sizeof(pesFilterParams)); if (On) { if (Handle->handle < 0) { Handle->handle = DvbOpen(DEV_DVB_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true); if (Handle->handle < 0) { LOG_ERROR; return false; } } pesFilterParams.pid = Handle->pid; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP; pesFilterParams.pes_type= PesTypes[Type < ptOther ? Type : ptOther]; pesFilterParams.flags = DMX_IMMEDIATE_START; if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { LOG_ERROR; return false; } } else if (!Handle->used) { CHECK(ioctl(Handle->handle, DMX_STOP)); if (Type <= ptTeletext) { pesFilterParams.pid = 0x1FFF; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_DECODER; pesFilterParams.pes_type= PesTypes[Type]; pesFilterParams.flags = DMX_IMMEDIATE_START; CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams)); if (PesTypes[Type] == DMX_PES_VIDEO) // let's only do this once SetPlayMode(pmNone); // necessary to switch a PID from DMX_PES_VIDEO/AUDIO to DMX_PES_OTHER } close(Handle->handle); Handle->handle = -1; } } return true; }
cSatipDevice::cSatipDevice(unsigned int indexP) : deviceIndexM(indexP), isPacketDeliveredM(false), isOpenDvrM(false), deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)), channelM() { unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE; bufsize -= (bufsize % TS_SIZE); isyslog("creating SAT>IP device %d (CardIndex=%d)", deviceIndexM, CardIndex()); tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false, *cString::sprintf("SAT>IP TS %d", deviceIndexM)); if (tsBufferM) { tsBufferM->SetTimeouts(100, 100); //tsBufferM->SetIoThrottle(); pTunerM = new cSatipTuner(*this, tsBufferM->Free()); } // Start section handler pSectionFilterHandlerM = new cSatipSectionFilterHandler(deviceIndexM, bufsize + 1); StartSectionHandler(); }
void SCDEVICE::LateInit(void) { DEBUGLOG("%s", __FUNCTION__); int n = CardIndex(); if (DeviceNumber() != n) ERRORLOG("CardIndex - DeviceNumber mismatch! Put DVBAPI plugin first on VDR commandline!"); softcsa = (fd_ca < 0); if (softcsa) { if (HasDecoder()) INFOLOG("Card %s is a full-featured card but no ca device found!", devId); } else if (cScDevices::ForceBudget(n)) { INFOLOG("Budget mode forced on card %s", devId); softcsa = true; } if (softcsa) { INFOLOG("Using software decryption on card %s", devId); } }
cSatipDevice::cSatipDevice(unsigned int indexP) : deviceIndexM(indexP), isPacketDeliveredM(false), isOpenDvrM(false), deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)), channelM(), createdM(0), mutexM() { unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE; bufsize -= (bufsize % TS_SIZE); info("Creating device CardIndex=%d DeviceNumber=%d [device %u]", CardIndex(), DeviceNumber(), deviceIndexM); tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false, *cString::sprintf("SATIP#%d TS", deviceIndexM)); if (tsBufferM) { tsBufferM->SetTimeouts(10, 10); tsBufferM->SetIoThrottle(); pTunerM = new cSatipTuner(*this, tsBufferM->Free()); } // Start section handler pSectionFilterHandlerM = new cSatipSectionFilterHandler(deviceIndexM, bufsize + 1); StartSectionHandler(); }
int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) { const char *FileName = *cDvbName(DEV_DVB_DEMUX, CardIndex()); int f = open(FileName, O_RDWR | O_NONBLOCK); if (f >= 0) { dmx_sct_filter_params sctFilterParams; memset(&sctFilterParams, 0, sizeof(sctFilterParams)); sctFilterParams.pid = Pid; sctFilterParams.timeout = 0; sctFilterParams.flags = DMX_IMMEDIATE_START; sctFilterParams.filter.filter[0] = Tid; sctFilterParams.filter.mask[0] = Mask; if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0) return f; else { esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask); close(f); } } else esyslog("ERROR: can't open filter handle on '%s'", FileName); return -1; }
bool cDvbDevice::SetPlayMode(ePlayMode PlayMode) { if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) { // reopen the devices fd_video = DvbOpen(DEV_DVB_VIDEO, CardIndex(), O_RDWR | O_NONBLOCK); fd_audio = DvbOpen(DEV_DVB_AUDIO, CardIndex(), O_RDWR | O_NONBLOCK); SetVideoFormat(Setup.VideoFormat); } switch (PlayMode) { case pmNone: // special handling to return from PCM replay: CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); CHECK(ioctl(fd_video, VIDEO_PLAY)); CHECK(ioctl(fd_video, VIDEO_STOP, true)); CHECK(ioctl(fd_audio, AUDIO_STOP, true)); CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); break; case pmAudioVideo: case pmAudioOnlyBlack: if (playMode == pmNone) TurnOffLiveMode(true); CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo)); CHECK(ioctl(fd_audio, AUDIO_PLAY)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); CHECK(ioctl(fd_video, VIDEO_PLAY)); break; case pmAudioOnly: CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_audio, AUDIO_STOP, true)); CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); CHECK(ioctl(fd_audio, AUDIO_PLAY)); CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); break; case pmVideoOnly: CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_video, VIDEO_STOP, true)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); CHECK(ioctl(fd_audio, AUDIO_PLAY)); CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); CHECK(ioctl(fd_video, VIDEO_PLAY)); break; case pmExtern_THIS_SHOULD_BE_AVOIDED: close(fd_video); close(fd_audio); fd_video = fd_audio = -1; break; } playMode = PlayMode; return true; }
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) { bool DoTune = !dvbTuner->IsTunedTo(Channel); bool TurnOffLivePIDs = HasDecoder() && (DoTune || !IsPrimaryDevice() || LiveView // for a new live view the old PIDs need to be turned off || pidHandles[ptVideo].pid == Channel->Vpid() // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER ); bool StartTransferMode = IsPrimaryDevice() && !DoTune && (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 || !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 ); bool TurnOnLivePIDs = HasDecoder() && !StartTransferMode && LiveView; #ifndef DO_MULTIPLE_RECORDINGS TurnOffLivePIDs = TurnOnLivePIDs = true; StartTransferMode = false; #endif // Turn off live PIDs if necessary: if (TurnOffLivePIDs) TurnOffLiveMode(LiveView); // Set the tuner: dvbTuner->Set(Channel, DoTune); // If this channel switch was requested by the EITScanner we don't wait for // a lock and don't set any live PIDs (the EITScanner will wait for the lock // by itself before setting any filters): if (EITScanner.UsesDevice(this)) //XXX return true; // PID settings: if (TurnOnLivePIDs) { SetAudioBypass(false); if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(Channel->Vpid(), ptVideo) && AddPid(Channel->Apid(0), ptAudio))) { esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1); return false; } if (IsPrimaryDevice()) AddPid(Channel->Tpid(), ptTeletext); CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schlüßler <*****@*****.**> this works // to avoid missing audio after replaying a DVD; with 'false' there is an audio disturbance when switching // between two channels on the same transponder on DVB-S CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); } else if (StartTransferMode) cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids())); return true; }
cDvbDevice::cDvbDevice(int n) { dvbTuner = NULL; frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN spuDecoder = NULL; digitalAudio = false; playMode = pmNone; // Devices that are present on all card types: int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK); // Devices that are only present on cards with decoders: fd_osd = DvbOpen(DEV_DVB_OSD, n, O_RDWR); fd_video = DvbOpen(DEV_DVB_VIDEO, n, O_RDWR | O_NONBLOCK); fd_audio = DvbOpen(DEV_DVB_AUDIO, n, O_RDWR | O_NONBLOCK); fd_stc = DvbOpen(DEV_DVB_DEMUX, n, O_RDWR); // The DVR device (will be opened and closed as needed): fd_dvr = -1; // The offset of the /dev/video devices: if (devVideoOffset < 0) { // the first one checks this FILE *f = NULL; char buffer[PATH_MAX]; for (int ofs = 0; ofs < 100; ofs++) { snprintf(buffer, sizeof(buffer), "/proc/video/dev/video%d", ofs); if ((f = fopen(buffer, "r")) != NULL) { if (fgets(buffer, sizeof(buffer), f)) { if (strstr(buffer, "DVB Board")) { // found the _first_ DVB card devVideoOffset = ofs; dsyslog("video device offset is %d", devVideoOffset); break; } } else break; fclose(f); } else break; } if (devVideoOffset < 0) devVideoOffset = 0; if (f) fclose(f); } devVideoIndex = (devVideoOffset >= 0 && HasDecoder()) ? devVideoOffset++ : -1; // Video format: SetVideoFormat(Setup.VideoFormat); // We only check the devices that must be present - the others will be checked before accessing them://XXX if (fd_frontend >= 0) { dvb_frontend_info feinfo; if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) { frontendType = feinfo.type; ciHandler = cCiHandler::CreateCiHandler(*cDvbName(DEV_DVB_CA, n)); dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType, ciHandler); } else LOG_ERROR; } else esyslog("ERROR: can't open DVB device %d", n); StartSectionHandler(); }
bool cDvbHdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) { int apid = Channel->Apid(0); int vpid = Channel->Vpid(); int dpid = Channel->Dpid(0); bool DoTune = !IsTunedToTransponder(Channel); bool pidHandlesVideo = vpid && pidHandles[ptVideo].pid == vpid; bool pidHandlesAudio = apid && pidHandles[ptAudio].pid == apid; bool TurnOffLivePIDs = DoTune || !IsPrimaryDevice() || LiveView // for a new live view the old PIDs need to be turned off || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER ; bool StartTransferMode = IsPrimaryDevice() && !DoTune && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER ); if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber())) StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN; //printf("SetChannelDevice Transfer %d, Live %d\n", StartTransferMode, LiveView); bool TurnOnLivePIDs = !StartTransferMode && LiveView; // Turn off live PIDs if necessary: if (TurnOffLivePIDs) TurnOffLiveMode(LiveView); // Set the tuner: if (!cDvbDevice::SetChannelDevice(Channel, LiveView)) return false; // PID settings: if (TurnOnLivePIDs) { if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo, Channel->Vtype()) && AddPid(apid ? apid : dpid, ptAudio, apid ? 0 : Channel->Dtype(0)))) { esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1); return false; } } else if (StartTransferMode) cControl::Launch(new cTransferControl(this, Channel)); return true; }