diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2002-09-04 17:26:02 +0200 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2002-09-04 17:26:02 +0200 |
commit | 3e58bc64fece489778cdd2dc3df24c9bdca28779 (patch) | |
tree | d9e311dcb8d11f3436a9cd4f4a0e9b6b377e3a76 /dvbdevice.c | |
parent | 1967d0cd3d4b4b6295f31d8cef2895e2de1a71d9 (diff) | |
download | vdr-3e58bc64fece489778cdd2dc3df24c9bdca28779.tar.gz vdr-3e58bc64fece489778cdd2dc3df24c9bdca28779.tar.bz2 |
Implemented recording and replaying with a single DVB card
Diffstat (limited to 'dvbdevice.c')
-rw-r--r-- | dvbdevice.c | 382 |
1 files changed, 218 insertions, 164 deletions
diff --git a/dvbdevice.c b/dvbdevice.c index 52c7c3ba..084b66ea 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 1.8 2002/08/25 09:20:53 kls Exp $ + * $Id: dvbdevice.c 1.9 2002/09/04 13:46:03 kls Exp $ */ #include "dvbdevice.h" @@ -20,10 +20,12 @@ extern "C" { #include <linux/videodev.h> #ifdef NEWSTRUCT #include <linux/dvb/audio.h> +#include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> #include <linux/dvb/video.h> #else #include <ost/audio.h> +#include <ost/dmx.h> #include <ost/sec.h> #include <ost/video.h> #endif @@ -35,8 +37,6 @@ extern "C" { #include "status.h" #include "transfer.h" -#define MAXDVBDEVICES 4 - #define DEV_VIDEO "/dev/video" #ifdef NEWSTRUCT #define DEV_DVB_ADAPTER "/dev/dvb/adapter" @@ -91,10 +91,10 @@ cDvbDevice::cDvbDevice(int n) 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); - + #ifndef NEWSTRUCT // Devices that are only present on DVB-S cards: - + fd_sec = DvbOpen(DEV_DVB_SEC, n, O_RDWR); #endif @@ -179,15 +179,6 @@ void cDvbDevice::MakePrimaryDevice(bool On) cDvbOsd::SetDvbDevice(On ? this : NULL); } -bool cDvbDevice::CanBeReUsed(int Frequency, int Vpid) -{ - return Receiving() // to be reused the DVB device must already be receiving... - && frequency == Frequency // ...and tuned to the requested frequency... - && (!HasDecoder() // ...and either be a "budget card" which can receive multiple channels... - || pidHandles[ptVideo].pid == Vpid // ...or be a "full featured card" that's already tuned to the requested video PID - ); -} - bool cDvbDevice::HasDecoder(void) const { return fd_video >= 0 && fd_audio >= 0; @@ -235,10 +226,10 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz mem1[0] = tmp; mem1 += 3; } - + if (Quality < 0) Quality = 255; //XXX is this 'best'??? - + isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); FILE *f = fopen(FileName, "wb"); if (f) { @@ -253,11 +244,11 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz cinfo.image_height = vm.height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; - + jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, Quality, true); jpeg_start_compress(&cinfo, true); - + int rs = vm.width * 3; JSAMPROW rp[vm.height]; for (int k = 0; k < vm.height; k++) @@ -313,6 +304,14 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On) else { CHECK(ioctl(Handle->handle, DMX_STOP)); if (Handle->used == 0) { + dmxPesFilterParams pesFilterParams; + memset(&pesFilterParams, 0, sizeof(pesFilterParams)); + pesFilterParams.pid = 0x1FFF; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_DECODER; + pesFilterParams.pesType = PesTypes[Type < ptOther ? Type : ptOther]; + pesFilterParams.flags = DMX_IMMEDIATE_START; + CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams)); close(Handle->handle); Handle->handle = -1; return true; @@ -339,8 +338,58 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On) return true; } -bool cDvbDevice::SetChannelDevice(const cChannel *Channel) +bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsSwitchChannel) { + bool result = false; + bool hasPriority = Priority < 0 || Priority > this->Priority(); + bool needsSwitchChannel = true; + + if (ProvidesCa(Channel->ca)) { + if (Receiving()) { + if (frequency == Channel->frequency) { + needsSwitchChannel = false; + if (!HasPid(Channel->vpid)) { + if (Channel->ca > CACONFBASE) { + needsSwitchChannel = true; + result = hasPriority; + } + else if (!HasDecoder()) + result = true; // if it has no decoder it can't be the primary device + else { +#define DVB_DRIVER_VERSION 2002090101 //XXX+ +#define MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT 2002090101 +#ifdef DVB_DRIVER_VERSION +#if (DVB_DRIVER_VERSION >= MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT) + if (pidHandles[ptVideo].used) + needsSwitchChannel = true; // to have it turn off the live PIDs + result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit; +#endif +#else +#warning "DVB_DRIVER_VERSION not defined - time shift with only one DVB device disabled!" +#endif + } + } + else + result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit; + } + else + result = hasPriority; + } + else + result = hasPriority; + } + if (NeedsSwitchChannel) + *NeedsSwitchChannel = needsSwitchChannel; + return result; +} + +bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) +{ +#if (DVB_DRIVER_VERSION < MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT) + if (HasDecoder()) + LiveView = true; +#endif + // Avoid noise while switching: if (HasDecoder()) { @@ -357,204 +406,209 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel) // Turn off current PIDs: - if (HasDecoder()) { + if (HasDecoder() && (LiveView || pidHandles[ptVideo].pid == Channel->vpid)) { DelPid(pidHandles[ptVideo].pid); DelPid(pidHandles[ptAudio].pid); DelPid(pidHandles[ptTeletext].pid); DelPid(pidHandles[ptDolby].pid); } + if (frequency != Channel->frequency || Channel->ca > CACONFBASE) { // CA channels can only be decrypted in "live" mode + #ifdef NEWSTRUCT - dvb_frontend_parameters Frontend; + dvb_frontend_parameters Frontend; #else - FrontendParameters Frontend; + FrontendParameters Frontend; #endif - memset(&Frontend, 0, sizeof(Frontend)); + memset(&Frontend, 0, sizeof(Frontend)); - switch (frontendType) { - case FE_QPSK: { // DVB-S + switch (frontendType) { + case FE_QPSK: { // DVB-S - // Frequency offsets: + // Frequency offsets: - unsigned int freq = Channel->frequency; - int tone = SEC_TONE_OFF; + unsigned int freq = Channel->frequency; + int tone = SEC_TONE_OFF; - if (freq < (unsigned int)Setup.LnbSLOF) { - freq -= Setup.LnbFrequLo; - tone = SEC_TONE_OFF; - } - else { - freq -= Setup.LnbFrequHi; - tone = SEC_TONE_ON; - } + if (freq < (unsigned int)Setup.LnbSLOF) { + freq -= Setup.LnbFrequLo; + tone = SEC_TONE_OFF; + } + else { + freq -= Setup.LnbFrequHi; + tone = SEC_TONE_ON; + } #ifdef NEWSTRUCT - Frontend.frequency = freq * 1000UL; - Frontend.inversion = INVERSION_AUTO; - Frontend.u.qpsk.symbol_rate = Channel->srate * 1000UL; - Frontend.u.qpsk.fec_inner = FEC_AUTO; + Frontend.frequency = freq * 1000UL; + Frontend.inversion = INVERSION_AUTO; + Frontend.u.qpsk.symbol_rate = Channel->srate * 1000UL; + Frontend.u.qpsk.fec_inner = FEC_AUTO; #else - Frontend.Frequency = freq * 1000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL; - Frontend.u.qpsk.FEC_inner = FEC_AUTO; + Frontend.Frequency = freq * 1000UL; + Frontend.Inversion = INVERSION_AUTO; + Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL; + Frontend.u.qpsk.FEC_inner = FEC_AUTO; #endif - int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; + int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; - // DiSEqC: + // DiSEqC: #ifdef NEWSTRUCT - struct dvb_diseqc_master_cmd cmd = { {0xE0, 0x10, 0x38, 0xF0, 0x00, 0x00}, 4}; - cmd.msg[3] = 0xF0 | (((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0)); - - if (Setup.DiSEqC) - CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); - CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt)); - if (Setup.DiSEqC) { - usleep(15 * 1000); - CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); - usleep(15 * 1000); - CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, (Channel->diseqc / 4) % 2 ? SEC_MINI_B : SEC_MINI_A)); - usleep(15 * 1000); - } - CHECK(ioctl(fd_frontend, FE_SET_TONE, tone)); + struct dvb_diseqc_master_cmd cmd = { {0xE0, 0x10, 0x38, 0xF0, 0x00, 0x00}, 4}; + cmd.msg[3] = 0xF0 | (((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0)); + + if (Setup.DiSEqC) + CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt)); + if (Setup.DiSEqC) { + usleep(15 * 1000); + CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); + usleep(15 * 1000); + CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, (Channel->diseqc / 4) % 2 ? SEC_MINI_B : SEC_MINI_A)); + usleep(15 * 1000); + } + CHECK(ioctl(fd_frontend, FE_SET_TONE, tone)); #else - secCommand scmd; - scmd.type = 0; - scmd.u.diseqc.addr = 0x10; - scmd.u.diseqc.cmd = 0x38; - scmd.u.diseqc.numParams = 1; - scmd.u.diseqc.params[0] = 0xF0 | ((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); - - secCmdSequence scmds; - scmds.voltage = volt; - scmds.miniCommand = SEC_MINI_NONE; - scmds.continuousTone = tone; - scmds.numCommands = Setup.DiSEqC ? 1 : 0; - scmds.commands = &scmd; - - CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); + secCommand scmd; + scmd.type = 0; + scmd.u.diseqc.addr = 0x10; + scmd.u.diseqc.cmd = 0x38; + scmd.u.diseqc.numParams = 1; + scmd.u.diseqc.params[0] = 0xF0 | ((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); + + secCmdSequence scmds; + scmds.voltage = volt; + scmds.miniCommand = SEC_MINI_NONE; + scmds.continuousTone = tone; + scmds.numCommands = Setup.DiSEqC ? 1 : 0; + scmds.commands = &scmd; + + CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); #endif - } - break; - case FE_QAM: { // DVB-C + } + break; + case FE_QAM: { // DVB-C - // Frequency and symbol rate: + // Frequency and symbol rate: #ifdef NEWSTRUCT - Frontend.frequency = Channel->frequency * 1000000UL; - Frontend.inversion = INVERSION_AUTO; - Frontend.u.qam.symbol_rate = Channel->srate * 1000UL; - Frontend.u.qam.fec_inner = FEC_AUTO; - Frontend.u.qam.modulation = QAM_64; + Frontend.frequency = Channel->frequency * 1000000UL; + Frontend.inversion = INVERSION_AUTO; + Frontend.u.qam.symbol_rate = Channel->srate * 1000UL; + Frontend.u.qam.fec_inner = FEC_AUTO; + Frontend.u.qam.modulation = QAM_64; #else - Frontend.Frequency = Channel->frequency * 1000000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qam.SymbolRate = Channel->srate * 1000UL; - Frontend.u.qam.FEC_inner = FEC_AUTO; - Frontend.u.qam.QAM = QAM_64; + Frontend.Frequency = Channel->frequency * 1000000UL; + Frontend.Inversion = INVERSION_AUTO; + Frontend.u.qam.SymbolRate = Channel->srate * 1000UL; + Frontend.u.qam.FEC_inner = FEC_AUTO; + Frontend.u.qam.QAM = QAM_64; #endif - } - break; - case FE_OFDM: { // DVB-T + } + break; + case FE_OFDM: { // DVB-T - // Frequency and OFDM paramaters: + // Frequency and OFDM paramaters: #ifdef NEWSTRUCT - Frontend.frequency = Channel->frequency * 1000UL; - Frontend.inversion = INVERSION_AUTO; - Frontend.u.ofdm.bandwidth=BANDWIDTH_8_MHZ; - Frontend.u.ofdm.code_rate_HP = FEC_2_3; - Frontend.u.ofdm.code_rate_LP = FEC_1_2; - Frontend.u.ofdm.constellation = QAM_64; - Frontend.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - Frontend.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - Frontend.u.ofdm.hierarchy_information = HIERARCHY_NONE; + Frontend.frequency = Channel->frequency * 1000UL; + Frontend.inversion = INVERSION_AUTO; + Frontend.u.ofdm.bandwidth=BANDWIDTH_8_MHZ; + Frontend.u.ofdm.code_rate_HP = FEC_2_3; + Frontend.u.ofdm.code_rate_LP = FEC_1_2; + Frontend.u.ofdm.constellation = QAM_64; + Frontend.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + Frontend.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + Frontend.u.ofdm.hierarchy_information = HIERARCHY_NONE; #else - Frontend.Frequency = Channel->frequency * 1000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ; - Frontend.u.ofdm.HP_CodeRate=FEC_2_3; - Frontend.u.ofdm.LP_CodeRate=FEC_1_2; - Frontend.u.ofdm.Constellation=QAM_64; - Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K; - Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32; - Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE; + Frontend.Frequency = Channel->frequency * 1000UL; + Frontend.Inversion = INVERSION_AUTO; + Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ; + Frontend.u.ofdm.HP_CodeRate=FEC_2_3; + Frontend.u.ofdm.LP_CodeRate=FEC_1_2; + Frontend.u.ofdm.Constellation=QAM_64; + Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K; + Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32; + Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE; #endif - } - break; - default: - esyslog("ERROR: attempt to set channel with unknown DVB frontend type"); - return false; - } + } + break; + default: + esyslog("ERROR: attempt to set channel with unknown DVB frontend type"); + return false; + } #ifdef NEWSTRUCT - // Discard stale events: + // Discard stale events: - for (;;) { - dvb_frontend_event event; - if (ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) - break; - } + for (;;) { + dvb_frontend_event event; + if (ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) + break; + } #endif - // Tuning: + // Tuning: - CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); + CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); - // Wait for channel lock: + // Wait for channel lock: #ifdef NEWSTRUCT - FrontendStatus status = FrontendStatus(0); - for (int i = 0; i < 100; i++) { - CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status)); - if (status & FE_HAS_LOCK) - break; - usleep(10 * 1000); - } - if (!(status & FE_HAS_LOCK)) { - esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->number, CardIndex() + 1); - if (IsPrimaryDevice()) - cThread::RaisePanic(); - return false; - } + FrontendStatus status = FrontendStatus(0); + for (int i = 0; i < 100; i++) { + CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status)); + if (status & FE_HAS_LOCK) + break; + usleep(10 * 1000); + } + if (!(status & FE_HAS_LOCK)) { + esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->number, CardIndex() + 1); + if (IsPrimaryDevice()) + cThread::RaisePanic(); + return false; + } #else - if (cFile::FileReady(fd_frontend, 5000)) { - FrontendEvent event; - if (ioctl(fd_frontend, FE_GET_EVENT, &event) >= 0) { - if (event.type != FE_COMPLETION_EV) { - esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->number, CardIndex() + 1); - if (IsPrimaryDevice()) - cThread::RaisePanic(); - return false; + if (cFile::FileReady(fd_frontend, 5000)) { + FrontendEvent event; + if (ioctl(fd_frontend, FE_GET_EVENT, &event) >= 0) { + if (event.type != FE_COMPLETION_EV) { + esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->number, CardIndex() + 1); + if (IsPrimaryDevice()) + cThread::RaisePanic(); + return false; + } } + else + esyslog("ERROR in frontend get event (channel %d, card %d): %m", Channel->number, CardIndex() + 1); } else - esyslog("ERROR in frontend get event (channel %d, card %d): %m", Channel->number, CardIndex() + 1); - } - else - esyslog("ERROR: timeout while tuning on DVB card %d", CardIndex() + 1); + esyslog("ERROR: timeout while tuning on DVB card %d", CardIndex() + 1); #endif - frequency = Channel->frequency; + frequency = Channel->frequency; + + } // PID settings: - if (HasDecoder()) { - if (!(AddPid(Channel->vpid, ptVideo) && AddPid(Channel->apid1, ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached) - esyslog("ERROR: failed to set PIDs for channel %d", Channel->number); - return false; + if (HasDecoder() && (LiveView || Channel->ca > CACONFBASE)) { // CA channels can only be decrypted in "live" mode + if (!HasPid(Channel->vpid)) { + if (!(AddPid(Channel->vpid, ptVideo) && AddPid(Channel->apid1, ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached) + esyslog("ERROR: failed to set PIDs for channel %d", Channel->number); + return false; + } + if (IsPrimaryDevice()) + AddPid(Channel->tpid, ptTeletext); + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); } - if (IsPrimaryDevice()) - AddPid(Channel->tpid, ptTeletext); - CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); - } - - if (HasDecoder()) { - CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); - CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); + else + cControl::Launch(new cTransferControl(this, Channel->vpid, Channel->apid1, 0, 0, 0)); } // Start setting system time: |