From a9b2afd28b878f932f98983e5e4e4f780ac6a7fe Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 3 Jun 2001 13:07:20 +0200 Subject: [PATCH] Support for two audio channels --- FORMATS | 2 +- HISTORY | 11 +++++++++++ MANUAL | 13 +++++++++++- config.c | 25 ++++++++++++++++------- config.h | 4 ++-- dvbapi.c | 60 ++++++++++++++++++++++++++++++++++++++++++++------------ dvbapi.h | 8 +++++--- i18n.c | 24 +++++++++++++++++------ menu.c | 29 ++++++++++++++++----------- remux.c | 16 ++++++++++++++- remux.h | 3 ++- 11 files changed, 149 insertions(+), 46 deletions(-) diff --git a/FORMATS b/FORMATS index 9d2c8f92..3a70871e 100644 --- a/FORMATS +++ b/FORMATS @@ -25,7 +25,7 @@ Video Disk Recorder File Formats - Diseqc number ** - Symbol rate - Video PID - - Audio PID + - Audio PID (either one number, or two, separated by a comma) - Teletext PID - Conditional Access (0 = Free To Air, 1 = can be decrypted by the first DVB card, 2 = can be decrypted by the second DVB card) diff --git a/HISTORY b/HISTORY index 1927a81d..07d12404 100644 --- a/HISTORY +++ b/HISTORY @@ -490,3 +490,14 @@ Video Disk Recorder Revision History a new recording with higher priority needs disk space. - Updated version of Matthias Schniedermeyer's 'schnitt' tools. - New 'master-timer' tool (thanks to Matthias Schniedermeyer). + +2001-06-03: Version 0.81 + +- Fixed handling the case where the driver reports EAGAIN during recording, + but no data comes within 5 seconds. +- Fixed EPG scanning on single DVB card systems. +- There can now be two audio PIDs per channel, which can be toggled via the + "Green" button in the "Main" menu. The "Edit Channel" menu therefore now + has two audio PID fields (Apid1 and Apid2). By default, Apid2 is 0, which + means there is no alternate audio track. + diff --git a/MANUAL b/MANUAL index cc9f9dae..9a72c512 100644 --- a/MANUAL +++ b/MANUAL @@ -18,7 +18,7 @@ Video Disk Recorder User's Manual Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Back - Menu off Main menu Main menu Discard Main menu Recordings menu Red - Record Edit Edit - Play - - Green - - New New - Rewind Skip -60s + Green - Language New New - Rewind Skip -60s Yellow - - Delete Delete - Delete Skip +60s Blue - Resume Mark Mark - Summary Stop 0..9 Ch select - - - Numeric inp. - Editing @@ -115,6 +115,14 @@ Video Disk Recorder User's Manual To bring up the channel display without switching channels you can press the "Ok" button. +* Selecting language specific audio track + + If the current channel provides different audio tracks (typically for + different languages), the "Green" button in the "Main" menu can be pressed + to toggle between these. There can be two different audio PIDs per channel, + assuming that typically a channel broadcasts a country specific language + plus the movie's original soundtrack. + * Switching through channel groups If the 'channels.conf' file contains "group separators" you can switch @@ -257,6 +265,9 @@ Video Disk Recorder User's Manual to free up space for a new recording. Note that setting this parameter to very high values for all recordings may soon fill up the entire disk and cause new recordings to fail due to low disk + space. The special value 99 means that this recording will live + "forever", and a value of 0 means that this recording can be + deleted any time if a recording with a higher priority needs disk space. File: The name under which a recording created through this timer will be stored on disk (the actual name will also contain the date and diff --git a/config.c b/config.c index 5c572357..bd3d83bf 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.45 2001/06/02 09:42:25 kls Exp $ + * $Id: config.c 1.46 2001/06/02 13:57:25 kls Exp $ */ #include "config.h" @@ -200,7 +200,8 @@ cChannel::cChannel(const cChannel *Channel) diseqc = Channel ? Channel->diseqc : 0; srate = Channel ? Channel->srate : 27500; vpid = Channel ? Channel->vpid : 255; - apid = Channel ? Channel->apid : 256; + apid1 = Channel ? Channel->apid1 : 256; + apid2 = Channel ? Channel->apid2 : 0; tpid = Channel ? Channel->tpid : 32; ca = Channel ? Channel->ca : 0; pnr = Channel ? Channel->pnr : 0; @@ -218,8 +219,15 @@ const char *cChannel::ToText(cChannel *Channel) delete buffer; if (Channel->groupSep) asprintf(&buffer, ":%s\n", s); - else - asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->tpid, Channel->ca, Channel->pnr); + else { + char apidbuf[20]; + char *q = apidbuf; + q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1); + if (Channel->apid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->apid2); + *q = 0; + asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%s:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, apidbuf, Channel->tpid, Channel->ca, Channel->pnr); + } return buffer; } @@ -242,8 +250,11 @@ bool cChannel::Parse(const char *s) } else { groupSep = false; - //XXX - int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &tpid, &ca, &pnr); + char *apidbuf = NULL; + int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%a[^:]:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apidbuf, &tpid, &ca, &pnr); + apid1 = apid2 = 0; + sscanf(apidbuf, "%d,%d", &apid1, &apid2); + delete apidbuf; if (fields >= 9) { if (fields == 9) { // allow reading of old format @@ -275,7 +286,7 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log) isyslog(LOG_INFO, "switching to channel %d", number); } for (int i = 3; i--;) { - if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid, tpid, ca, pnr)) + if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, tpid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); } diff --git a/config.h b/config.h index 8665704f..bd2af18e 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.45 2001/06/02 09:43:04 kls Exp $ + * $Id: config.h 1.46 2001/06/02 12:26:13 kls Exp $ */ #ifndef __CONFIG_H @@ -95,7 +95,7 @@ public: int diseqc; int srate; int vpid; - int apid; + int apid1, apid2; int tpid; int ca; int pnr; diff --git a/dvbapi.c b/dvbapi.c index caed6fc3..80f66bdf 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.68 2001/06/02 12:20:13 kls Exp $ + * $Id: dvbapi.c 1.69 2001/06/03 13:07:20 kls Exp $ */ #include "dvbapi.h" @@ -1018,6 +1018,7 @@ class cTransferBuffer : public cRingBuffer { private: cDvbApi *dvbApi; int fromDevice, toDevice; + bool gotBufferReserve; cRemux remux; protected: virtual void Input(void); @@ -1025,6 +1026,7 @@ protected: public: cTransferBuffer(cDvbApi *DvbApi, int ToDevice, dvb_pid_t VPid, dvb_pid_t APid); virtual ~cTransferBuffer(); + void SetAudioPid(int APid); }; cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, dvb_pid_t VPid, dvb_pid_t APid) @@ -1034,6 +1036,7 @@ cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, dvb_pid_t VPid, dvbApi = DvbApi; fromDevice = dvbApi->SetModeRecord(); toDevice = ToDevice; + gotBufferReserve = false; Start(); } @@ -1043,6 +1046,15 @@ cTransferBuffer::~cTransferBuffer() dvbApi->SetModeNormal(true); } +void cTransferBuffer::SetAudioPid(int APid) +{ + Clear(); + //XXX we may need to have access to the audio device, too, in order to clear it + CHECK(ioctl(toDevice, VIDEO_CLEAR_BUFFER)); + gotBufferReserve = false; + remux.SetAudioPid(APid); +} + void cTransferBuffer::Input(void) { dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); @@ -1084,14 +1096,13 @@ void cTransferBuffer::Output(void) { dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); - bool GotBufferReserve = false; uchar b[MINVIDEODATA]; while (Busy()) { - if (!GotBufferReserve) { + if (!gotBufferReserve) { if (Available() < MAXFRAMESIZE) usleep(100000); // allow the buffer to collect some reserve else - GotBufferReserve = true; + gotBufferReserve = true; } int r = Get(b, sizeof(b)); if (r > 0) { @@ -1302,7 +1313,7 @@ cDvbApi *cDvbApi::PrimaryDvbApi = NULL; cDvbApi::cDvbApi(int n) { - vPid = aPid = 0; + vPid = aPid1 = aPid2 = 0; siProcessor = NULL; recordBuffer = NULL; replayBuffer = NULL; @@ -2010,11 +2021,11 @@ bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Ou bool cDvbApi::SetPids(bool ForRecording) { - return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && - SetApid(aPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER); + return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && + SetApid(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER); } -bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr) +bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Tpid, int Ca, int Pnr) { // Make sure the siProcessor won't access the device while switching cThreadLock ThreadLock(siProcessor); @@ -2127,7 +2138,8 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, // PID settings: vPid = Vpid; - aPid = Apid; + aPid1 = Apid1; + aPid2 = Apid2; if (!SetPids(false)) { esyslog(LOG_ERR, "ERROR: failed to set PIDs for channel %d", ChannelNumber); return false; @@ -2146,7 +2158,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); if (CaDvbApi) { if (!CaDvbApi->Recording()) { - if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) { + if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Tpid, Ca, Pnr)) { SetModeReplay(); transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); } @@ -2161,6 +2173,28 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, return true; } +bool cDvbApi::CanToggleAudioPid(void) +{ + return aPid1 && aPid2 && aPid1 != aPid2; +} + +bool cDvbApi::ToggleAudioPid(void) +{ + if (CanToggleAudioPid()) { + int a = aPid2; + aPid2 = aPid1; + aPid1 = a; + if (transferringFromDvbApi) + return transferringFromDvbApi->ToggleAudioPid(); + else { + if (transferBuffer) + transferBuffer->SetAudioPid(aPid1); + return SetPids(transferBuffer != NULL); + } + } + return false; +} + bool cDvbApi::Transferring(void) { return transferBuffer; @@ -2169,7 +2203,7 @@ bool cDvbApi::Transferring(void) cDvbApi *cDvbApi::StartTransfer(int TransferToVideoDev) { StopTransfer(); - transferBuffer = new cTransferBuffer(this, TransferToVideoDev, vPid, aPid); + transferBuffer = new cTransferBuffer(this, TransferToVideoDev, vPid, aPid1); return this; } @@ -2230,7 +2264,7 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) // Create recording buffer: - recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid); + recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1); if (recordBuffer) { ca = Ca; @@ -2384,7 +2418,7 @@ void cEITScanner::Process(void) time_t now = time(NULL); if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { for (int i = 0; i < cDvbApi::NumDvbApis; i++) { - cDvbApi *DvbApi = cDvbApi::GetDvbApi(i + 1, 0); + cDvbApi *DvbApi = cDvbApi::GetDvbApi(i + 1, MAXPRIORITY); if (DvbApi) { if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) { if (!(DvbApi->Recording() || DvbApi->Replaying() || DvbApi->Transferring())) { diff --git a/dvbapi.h b/dvbapi.h index f9808299..e9b59cdc 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.36 2001/06/02 09:44:00 kls Exp $ + * $Id: dvbapi.h 1.37 2001/06/03 11:51:30 kls Exp $ */ #ifndef __DVBAPI_H @@ -67,7 +67,7 @@ class cDvbApi { private: int videoDev; int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa, fd_demuxv, fd_demuxt; - int vPid, aPid; + int vPid, aPid1, aPid2; bool SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Output); bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); } bool SetApid(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa, DMX_PES_AUDIO, Apid, Output); } @@ -177,9 +177,11 @@ public: private: int currentChannel; public: - bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr); + bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Tpid, int Ca, int Pnr); static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } int Channel(void) { return currentChannel; } + bool CanToggleAudioPid(void); + bool ToggleAudioPid(void); // Transfer facilities diff --git a/i18n.c b/i18n.c index 87da256d..02fc7ceb 100644 --- a/i18n.c +++ b/i18n.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.17 2001/06/02 09:39:36 kls Exp $ + * $Id: i18n.c 1.18 2001/06/03 12:57:21 kls Exp $ * * Slovenian translations provided by Miha Setina * Italian translations provided by Alberto Carraro @@ -225,6 +225,12 @@ const tPhrase Phrases[] = { "Programma", "Programma", }, + { "Language", + "Sprache", + "Jezik", + "Linguaggio", + "Taal", + }, // Confirmations: { "Delete channel?", "Kanal löschen?", @@ -293,11 +299,17 @@ const tPhrase Phrases[] = { "Vpid", "Vpid", }, - { "Apid", - "Apid", - "Apid", - "Apid", - "Apid", + { "Apid1", + "Apid1", + "Apid1", + "Apid1", + "Apid1", + }, + { "Apid2", + "Apid2", + "Apid2", + "Apid2", + "Apid2", }, { "Tpid", "Tpid", diff --git a/menu.c b/menu.c index 456ac137..d45ac8dd 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.71 2001/06/02 09:59:54 kls Exp $ + * $Id: menu.c 1.72 2001/06/02 13:51:28 kls Exp $ */ #include "menu.h" @@ -540,7 +540,8 @@ cMenuEditChannel::cMenuEditChannel(int Index) Add(new cMenuEditIntItem( tr("Diseqc"), &data.diseqc, 0, 10)); //TODO exact limits??? Add(new cMenuEditIntItem( tr("Srate"), &data.srate, 22000, 27500)); //TODO exact limits - toggle??? Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0xFFFE)); - Add(new cMenuEditIntItem( tr("Apid"), &data.apid, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0xFFFE)); + Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0xFFFE)); Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0xFFFE)); Add(new cMenuEditIntItem( tr("CA"), &data.ca, 0, cDvbApi::NumDvbApis)); Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); @@ -1725,7 +1726,7 @@ cMenuMain::cMenuMain(bool Replaying) } if (cVideoCutter::Active()) Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); - SetHelp(tr("Record"), NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); + SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioPid() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); Display(); lastActivity = time(NULL); SetHasHotkeys(); @@ -1756,14 +1757,20 @@ eOSState cMenuMain::ProcessKey(eKeys Key) } break; default: switch (Key) { - case kMenu: state = osEnd; break; - case kRed: if (!HasSubMenu()) - state = osRecord; - break; - case kBlue: if (!HasSubMenu()) - state = osReplay; - break; - default: break; + case kMenu: state = osEnd; break; + case kRed: if (!HasSubMenu()) + state = osRecord; + break; + case kGreen: if (cDvbApi::PrimaryDvbApi->CanToggleAudioPid()) { + Interface->Clear(); + cDvbApi::PrimaryDvbApi->ToggleAudioPid(); + state = osEnd; + } + break; + case kBlue: if (!HasSubMenu()) + state = osReplay; + break; + default: break; } } if (Key != kNone) diff --git a/remux.c b/remux.c index 6212ff07..1fdb579d 100644 --- a/remux.c +++ b/remux.c @@ -8,7 +8,7 @@ * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit * VDR's needs. * - * $Id: remux.c 1.2 2001/05/27 10:27:15 kls Exp $ + * $Id: remux.c 1.3 2001/06/02 15:39:16 kls Exp $ */ /* The calling interface of the 'cRemux::Process()' function is defined @@ -135,6 +135,7 @@ public: cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size); ~cTS2PES(); void ts_to_pes(const uint8_t *Buf); // don't need count (=188) + void Clear(void); }; uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 }; @@ -156,6 +157,11 @@ cTS2PES::~cTS2PES() delete buf; } +void cTS2PES::Clear(void) +{ + reset_ipack(); +} + void cTS2PES::store(uint8_t *Data, int Count) { //XXX overflow check??? @@ -455,6 +461,14 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic return -1; } +void cRemux::SetAudioPid(int APid) +{ + aPid = APid; + vTS2PES->Clear(); + aTS2PES->Clear(); + resultCount = resultDelivered = 0; +} + const uchar *cRemux::Process(const uchar *Data, int &Count, int &Result, uchar *PictureType) { uchar dummyPictureType; diff --git a/remux.h b/remux.h index 6705e341..011dd3b6 100644 --- a/remux.h +++ b/remux.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.h 1.2 2001/05/26 11:50:52 kls Exp $ + * $Id: remux.h 1.3 2001/06/02 15:15:43 kls Exp $ */ #ifndef __REMUX_H @@ -50,6 +50,7 @@ private: public: cRemux(dvb_pid_t VPid, dvb_pid_t APid, bool ExitOnFailure = false); ~cRemux(); + void SetAudioPid(int APid); const uchar *Process(const uchar *Data, int &Count, int &Result, uchar *PictureType = NULL); };