diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-02-24 18:00:00 +0100 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2001-02-24 18:00:00 +0100 |
commit | f2937af95ceaf3a52c327e96571367ef5475b3a1 (patch) | |
tree | 6a4e39714b5741d9dfcb90bdff3e6487f06e07fa /dvbapi.c | |
parent | 3fe3c15d5db9c1f3982ffe6dac1ae4ad56d1664d (diff) | |
download | vdr-patch-lnbsharing-f2937af95ceaf3a52c327e96571367ef5475b3a1.tar.gz vdr-patch-lnbsharing-f2937af95ceaf3a52c327e96571367ef5475b3a1.tar.bz2 |
Version 0.71vdr-0.71
- Fixed 'Transfer Mode' in cases where a non-primary interface was switched to
a channel that only the primary interface can receive (which could happen in
the EPG scanner).
- The EPG scanner now starts with the first channel (it used to start with the
second channel).
- Reacitvated setting the PNR.
- Adapted the frame scanning to the new muxing of the driver.
- The new compile time option REMOTE=NONE can be used to compile VDR without
any remote control support (for applications where it shall be controlled
exclusively via SVDRP).
- The new command line option -D can be used to define which DVB interfaces
a certain instance of VDR shall use.
- The "Left" and "Right" keys are now used to page up and down in lists (thanks
to Martin Hammerschmid). Since the "Timers" menu already uses these keys to
(de)activate timers, this functionality is not available there.
- The "Main" and "Commands" menu now support "hotkeys", which means that if the
first non-blank character of a menu item is a digit in the range 1..9, that
item can be selected by pressing the respective numeric key on the remote
control.
- The channel data in 'channels.conf' now contains the teletext PID (thanks to
Dave Chapman). Existing files will be read normally (and the teletext PID set
to 0), but once they are written back (due to some channel editing) the file
will have the new format.
- The EPG scanner now scans each transponder only once per cycle.
- Deleted recordings are now automatically removed from disk after a while (not
only when disk space is being needed for a new recording).
- Fixed repeat function in LIRC remote control.
- Changed the MAXDVBAPI macro in dvbapi.c to 4 in order to directly support the
maximum possible number of DVB cards.
- The 'Ca' parameter in the default 'channels.conf' has been changed from '2'
to '3' because the VDR prototype now has 3 DVB cards (and currently the CAM
module only works if it is inserted into the last DVB card).
- The "Now", "Next" and "Schedule" menus now remember the current channel and
restore the list when switching between them.
- The "Green" button in the "Recordings" menu can now be used to rewind a
recording and play it from the very beginning.
- Fixed handling ':' in timer filenames and '\n' in timer summaries (see FORMATS).
- When removing recordings empty directories are now removed from the video
directory.
- Added the "schnitt" tools from Matthias Schniedermeyer.
- New SVDRP command MESG to display a short message on the OSD.
- The Perl script 'svdrpsend.pl' can be used to send SVDRP commands to VDR.
- SVDRP can now immediately reuse the same port if VDR is restarted.
- SVDRP now has a timeout after which the connection is automatically closed
(default is 300 seconds, can be changed in "Setup").
- The compile time switch VFAT can be used to make VDR avoid the ':' character
in file names (VFAT can't handle them). Do 'make VFAT=1' to enable this.
- Support for DVB-C (thanks to Hans-Peter Raschke and Peter Hofmann).
See the INSTALL file for more information about the use of VDR with cable.
- Fixed an occasional segfault in the EIT processor.
- A value of '0' for the EPGScanTimeout setup parameter now completely turns off
scanning for EPG data on both single and multiple card systems.
- New setup parameter "PrimaryLimit" that allows to prevent timers from using the
primary DVB interface in multi card systems. Default value is 0, which means
that every timer may use the primary interface.
- The 'active' field of a timer will now be explicitly set to '1' if the user
modifies an active timer (see FORMATS for details).
- The new command line option -w can be used to activate a watchdog that makes
VDR exit in case the main program loop does not respond for more than the
given number of seconds. This is mainly useful in combination with the new
'runvdr' script that restarts VDR in case is has exited.
Diffstat (limited to 'dvbapi.c')
-rw-r--r-- | dvbapi.c | 208 |
1 files changed, 100 insertions, 108 deletions
@@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.50 2001/01/18 19:53:54 kls Exp $ + * $Id: dvbapi.c 1.61 2001/02/24 13:13:19 kls Exp $ */ #include "dvbapi.h" @@ -67,7 +67,6 @@ extern "C" { #define DISKCHECKINTERVAL 100 // seconds #define INDEXFILESUFFIX "/index.vdr" -#define RESUMEFILESUFFIX "/resume.vdr" #define RECORDFILESUFFIX "/%03d.vdr" #define RECORDFILESUFFIXLEN 20 // some additional bytes for safety... @@ -105,56 +104,6 @@ int HMSFToIndex(const char *HMSF) return 0; } -// --- cResumeFile ------------------------------------------------------------ - -cResumeFile::cResumeFile(const char *FileName) -{ - fileName = new char[strlen(FileName) + strlen(RESUMEFILESUFFIX) + 1]; - if (fileName) { - strcpy(fileName, FileName); - strcat(fileName, RESUMEFILESUFFIX); - } - else - esyslog(LOG_ERR, "ERROR: can't allocate memory for resume file name"); -} - -cResumeFile::~cResumeFile() -{ - delete fileName; -} - -int cResumeFile::Read(void) -{ - int resume = -1; - if (fileName) { - int f = open(fileName, O_RDONLY); - if (f >= 0) { - if (read(f, &resume, sizeof(resume)) != sizeof(resume)) { - resume = -1; - LOG_ERROR_STR(fileName); - } - close(f); - } - else if (errno != ENOENT) - LOG_ERROR_STR(fileName); - } - return resume; -} - -bool cResumeFile::Save(int Index) -{ - if (fileName) { - int f = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); - if (f >= 0) { - if (write(f, &Index, sizeof(Index)) != sizeof(Index)) - LOG_ERROR_STR(fileName); - close(f); - return true; - } - } - return false; -} - // --- cIndexFile ------------------------------------------------------------ class cIndexFile { @@ -821,7 +770,9 @@ int cRecordBuffer::ScanVideoPacket(int *PictureType, int Offset) int Length = GetPacketLength(Offset); if (Length <= Available()) { - for (int i = Offset; i < Offset + Length; i++) { + int i = Offset + 8; // the minimum length of the video packet header + i += Byte(i) + 1; // possible additional header bytes + for (; i < Offset + Length; i++) { if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { switch (Byte(i + 3)) { case SC_PICTURE: *PictureType = GetPictureType(i); @@ -840,8 +791,6 @@ int cRecordBuffer::Synchronize(void) // Positions to the start of a data block (skipping everything up to // an I-frame if not synced) and returns the block length. - int LastPackHeader = -1; - pictureType = NO_PICTURE; //XXX remove this once the buffer is handled with two separate threads: @@ -853,8 +802,6 @@ int cRecordBuffer::Synchronize(void) for (int i = 0; Available() > MINVIDEODATA && i < MINVIDEODATA; i++) { if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { switch (Byte(i + 3)) { - case SC_PHEAD: LastPackHeader = i; - break; case SC_VIDEO: { int pt = NO_PICTURE; int l = ScanVideoPacket(&pt, i); @@ -862,21 +809,15 @@ int cRecordBuffer::Synchronize(void) return 0; // no useful data found, wait for more if (pt != NO_PICTURE) { if (pt < I_FRAME || B_FRAME < pt) { - esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); - } + esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt); + } else if (pictureType == NO_PICTURE) { if (!synced) { - if (LastPackHeader == 0) { - if (pt == I_FRAME) - synced = true; - } - else if (LastPackHeader > 0) { - Skip(LastPackHeader); - LastPackHeader = -1; - i = 0; - break; + if (pt == I_FRAME) { + Skip(i); + synced = true; } - else { // LastPackHeader < 0 + else { Skip(i + l); i = 0; break; @@ -885,13 +826,15 @@ int cRecordBuffer::Synchronize(void) if (synced) pictureType = pt; } - else if (LastPackHeader > 0) - return LastPackHeader; else return i; } + else if (!synced) { + Skip(i + l); + i = 0; + break; + } i += l - 1; // -1 to compensate for i++ in the loop! - LastPackHeader = -1; } break; case SC_AUDIO: i += GetPacketLength(i) - 1; // -1 to compensate for i++ in the loop! @@ -1576,6 +1519,7 @@ bool cVideoCutter::Active(void) // --- cDvbApi --------------------------------------------------------------- int cDvbApi::NumDvbApis = 0; +int cDvbApi::useDvbApi = 0; cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; cDvbApi *cDvbApi::PrimaryDvbApi = NULL; @@ -1645,6 +1589,12 @@ cDvbApi::~cDvbApi() #endif } +void cDvbApi::SetUseDvbApi(int n) +{ + if (n < MAXDVBAPI) + useDvbApi |= (1 << n); +} + bool cDvbApi::SetPrimaryDvbApi(int n) { n--; @@ -1659,7 +1609,7 @@ bool cDvbApi::SetPrimaryDvbApi(int n) cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) { - cDvbApi *d = NULL; + cDvbApi *d = NULL, *dMinPriority = NULL; int index = Ca - 1; for (int i = MAXDVBAPI; --i >= 0; ) { if (dvbApi[i]) { @@ -1669,13 +1619,25 @@ cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority) } else if (Ca == 0) { // means any device would be acceptable if (!d || !dvbApi[i]->Recording() || (d->Recording() && d->Priority() > dvbApi[i]->Priority())) - d = dvbApi[i]; + d = dvbApi[i]; // this is one that is either not currently recording or has the lowest priority if (d && d != PrimaryDvbApi && !d->Recording()) // avoids the PrimaryDvbApi if possible break; + if (d && d->Recording() && d->Priority() < Setup.PrimaryLimit && (!dMinPriority || d->Priority() < dMinPriority->Priority())) + dMinPriority = d; // this is the one with the lowest priority below Setup.PrimaryLimit } } } - return (d && (!d->Recording() || d->Priority() < Priority || (!d->Ca() && Ca))) ? d : NULL; + if (d == PrimaryDvbApi) { // the PrimaryDvbApi was the only one that was free + if (Priority < Setup.PrimaryLimit) + return NULL; // not enough priority to use the PrimaryDvbApi + if (dMinPriority) // there's one that must not use the PrimaryDvbApi... + d = dMinPriority; // ...so let's kick out that one + } + return (d // we found one... + && (!d->Recording() // ...that's either not currently recording... + || d->Priority() < Priority // ...or has a lower priority... + || (!d->Ca() && Ca))) // ...or doesn't need this card + ? d : NULL; } int cDvbApi::Index(void) @@ -1691,33 +1653,34 @@ bool cDvbApi::Init(void) { NumDvbApis = 0; for (int i = 0; i < MAXDVBAPI; i++) { - char fileName[strlen(VIDEODEVICE) + 10]; - sprintf(fileName, "%s%d", VIDEODEVICE, i); - if (access(fileName, F_OK | R_OK | W_OK) == 0) { - dsyslog(LOG_INFO, "probing %s", fileName); - int f = open(fileName, O_RDWR); - if (f >= 0) { - struct video_capability cap; - int r = ioctl(f, VIDIOCGCAP, &cap); - close(f); - if (r == 0 && (cap.type & VID_TYPE_DVB)) { - char vbiFileName[strlen(VBIDEVICE) + 10]; - sprintf(vbiFileName, "%s%d", VBIDEVICE, i); - dvbApi[i] = new cDvbApi(fileName, vbiFileName); - NumDvbApis++; + if (useDvbApi == 0 || (useDvbApi & (1 << i)) != 0) { + char fileName[strlen(VIDEODEVICE) + 10]; + sprintf(fileName, "%s%d", VIDEODEVICE, i); + if (access(fileName, F_OK | R_OK | W_OK) == 0) { + dsyslog(LOG_INFO, "probing %s", fileName); + int f = open(fileName, O_RDWR); + if (f >= 0) { + struct video_capability cap; + int r = ioctl(f, VIDIOCGCAP, &cap); + close(f); + if (r == 0 && (cap.type & VID_TYPE_DVB)) { + char vbiFileName[strlen(VBIDEVICE) + 10]; + sprintf(vbiFileName, "%s%d", VBIDEVICE, i); + dvbApi[NumDvbApis++] = new cDvbApi(fileName, vbiFileName); + } + } + else { + if (errno != ENODEV) + LOG_ERROR_STR(fileName); + break; } } else { - if (errno != ENODEV) + if (errno != ENOENT) LOG_ERROR_STR(fileName); break; } } - else { - if (errno != ENOENT) - LOG_ERROR_STR(fileName); - break; - } } PrimaryDvbApi = dvbApi[0]; if (NumDvbApis > 0) { @@ -2168,7 +2131,7 @@ void cDvbApi::Flush(void) #endif } -bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr) +bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr) { if (videoDev >= 0) { cThreadLock ThreadLock(siProcessor); // makes sure the siProcessor won't access the vbi-device while switching @@ -2177,20 +2140,29 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, struct frontend front; ioctl(videoDev, VIDIOCGFRONTEND, &front); unsigned int freq = FrequencyMHz; - front.ttk = (freq < 11700UL) ? 0 : 1; - if (freq < 11700UL) - freq -= Setup.LnbFrequLo; - else - freq -= Setup.LnbFrequHi; - front.pnr = 0; + if (front.type == FRONT_DVBS) { + front.ttk = (freq < 11700UL) ? 0 : 1; + if (freq < 11700UL) { + freq -= Setup.LnbFrequLo; + front.ttk = 0; + } + else { + freq -= Setup.LnbFrequHi; + front.ttk = 1; + } + } + front.channel_flags = Ca ? DVB_CHANNEL_CA : DVB_CHANNEL_FTA; + front.pnr = Pnr; front.freq = freq * 1000000UL; front.diseqc = Diseqc; front.srate = Srate * 1000; front.volt = (Polarization == 'v' || Polarization == 'V') ? 0 : 1; front.video_pid = Vpid; front.audio_pid = Apid; + front.tt_pid = Tpid; front.fec = 8; front.AFC = 1; + front.qam = 2; ioctl(videoDev, VIDIOCSFRONTEND, &front); if (front.sync & 0x1F == 0x1F) { if (this == PrimaryDvbApi && siProcessor) @@ -2198,11 +2170,11 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, currentChannel = ChannelNumber; // If this DVB card can't receive this channel, let's see if we can // use the card that actually can receive it and transfer data from there: - if (Ca && Ca != Index() + 1) { + if (this == PrimaryDvbApi && Ca && Ca != Index() + 1) { cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); if (CaDvbApi) { if (!CaDvbApi->Recording()) { - if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Ca, Pnr)) + if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) transferringFromDvbApi = CaDvbApi->StartTransfer(videoDev); } } @@ -2403,7 +2375,25 @@ cEITScanner::cEITScanner(void) { lastScan = lastActivity = time(NULL); currentChannel = 0; - lastChannel = 1; + lastChannel = 0; + numTransponders = 0; + transponders = NULL; +} + +cEITScanner::~cEITScanner() +{ + delete transponders; +} + +bool cEITScanner::TransponderScanned(cChannel *Channel) +{ + for (int i = 0; i < numTransponders; i++) { + if (transponders[i] == Channel->frequency) + return true; + } + transponders = (int *)realloc(transponders, ++numTransponders * sizeof(int)); + transponders[numTransponders - 1] = Channel->frequency; + return false; } void cEITScanner::Activity(void) @@ -2417,7 +2407,7 @@ void cEITScanner::Activity(void) void cEITScanner::Process(void) { - if (Channels.MaxNumber() > 1) { + if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) { time_t now = time(NULL); if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { for (int i = 0; i < cDvbApi::NumDvbApis; i++) { @@ -2428,10 +2418,12 @@ void cEITScanner::Process(void) int oldCh = lastChannel; int ch = oldCh + 1; while (ch != oldCh) { - if (ch > Channels.MaxNumber()) + if (ch > Channels.MaxNumber()) { ch = 1; + numTransponders = 0; + } cChannel *Channel = Channels.GetByNumber(ch); - if (Channel && Channel->pnr) { + if (Channel && Channel->pnr && !TransponderScanned(Channel)) { if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel) currentChannel = DvbApi->Channel(); Channel->Switch(DvbApi, false); |