Support for two audio channels

This commit is contained in:
Klaus Schmidinger 2001-06-03 13:07:20 +02:00
parent b41adae497
commit a9b2afd28b
11 changed files with 149 additions and 46 deletions

View File

@ -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)

11
HISTORY
View File

@ -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.

13
MANUAL
View File

@ -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

View File

@ -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");
}

View File

@ -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;

View File

@ -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())) {

View File

@ -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

24
i18n.c
View File

@ -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 <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@ -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",

29
menu.c
View File

@ -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)

16
remux.c
View File

@ -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;

View File

@ -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);
};