summaryrefslogtreecommitdiff
path: root/dvbdevice.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2002-09-04 17:26:02 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2002-09-04 17:26:02 +0200
commit3e58bc64fece489778cdd2dc3df24c9bdca28779 (patch)
treed9e311dcb8d11f3436a9cd4f4a0e9b6b377e3a76 /dvbdevice.c
parent1967d0cd3d4b4b6295f31d8cef2895e2de1a71d9 (diff)
downloadvdr-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.c382
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: