Added Dolby Digital recording/replay

This commit is contained in:
Klaus Schmidinger 2001-06-24 17:42:19 +02:00
parent 947750f20b
commit d67fb2ce55
13 changed files with 188 additions and 73 deletions

View File

@ -26,6 +26,8 @@ Video Disk Recorder File Formats
- Symbol rate - Symbol rate
- Video PID - Video PID
- Audio PID (either one number, or two, separated by a comma) - Audio PID (either one number, or two, separated by a comma)
If this channel also carries Dolby Digital sound, the Dolby PIDs follow
the audio PIDs, separated by a semicolon, as in "...:101,102;103,104:..."
- Teletext PID - Teletext PID
- Conditional Access (0 = Free To Air, 1 = can be decrypted by the first - Conditional Access (0 = Free To Air, 1 = can be decrypted by the first
DVB card, 2 = can be decrypted by the second DVB card) DVB card, 2 = can be decrypted by the second DVB card)
@ -135,5 +137,6 @@ Video Disk Recorder File Formats
an individual file below a given limit, a recording is split into several an individual file below a given limit, a recording is split into several
files. The contents of these files is "Packetized Elementary Stream" (PES) files. The contents of these files is "Packetized Elementary Stream" (PES)
and contains ES packets with ids 0xE0 for video, 0xC0 for audio 1 and 0xC1 and contains ES packets with ids 0xE0 for video, 0xC0 for audio 1 and 0xC1
for audio 2 (if available). for audio 2 (if available). Dolby Digital data is stored in packets with
ids 0xBD.

View File

@ -526,8 +526,11 @@ Video Disk Recorder Revision History
- New setup parameter "VideoFormat" to define the aspect ratio of the tv set - New setup parameter "VideoFormat" to define the aspect ratio of the tv set
in use (4:3 or 16:9). in use (4:3 or 16:9).
2001-06-22: Version 0.83 2001-06-26: Version 0.83
- Avoiding "Device or resource busy" error message when setting PIDs. - Avoiding "Device or resource busy" error message when setting PIDs.
- Added Portugese language texts (Paulo Manuel Martins Lopes). - Added Portugese language texts (Paulo Manuel Martins Lopes).
- Recording and replaying Dolby Digital (AC3) sound.
- No longer getting stuck when a channel doesn't sync while switching
with the 'Up' and 'Down' keys.

View File

@ -88,6 +88,15 @@ Command line options:
Use "vdr --help" for a list of available command line options. Use "vdr --help" for a list of available command line options.
Replaying Dolby Digital audio:
------------------------------
To replay Dolby Digital audio you need a program that reads the DD data
from stdin and processes it in a way suitable for your audio hardware.
This program must be given to VDR with the '-a' option, as in
vdr -a ac3play
The video data directory: The video data directory:
------------------------- -------------------------

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.47 2001/06/16 14:06:56 kls Exp $ * $Id: config.c 1.48 2001/06/23 14:01:03 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -202,6 +202,8 @@ cChannel::cChannel(const cChannel *Channel)
vpid = Channel ? Channel->vpid : 255; vpid = Channel ? Channel->vpid : 255;
apid1 = Channel ? Channel->apid1 : 256; apid1 = Channel ? Channel->apid1 : 256;
apid2 = Channel ? Channel->apid2 : 0; apid2 = Channel ? Channel->apid2 : 0;
dpid1 = Channel ? Channel->dpid1 : 257;
dpid2 = Channel ? Channel->dpid2 : 0;
tpid = Channel ? Channel->tpid : 32; tpid = Channel ? Channel->tpid : 32;
ca = Channel ? Channel->ca : 0; ca = Channel ? Channel->ca : 0;
pnr = Channel ? Channel->pnr : 0; pnr = Channel ? Channel->pnr : 0;
@ -220,11 +222,15 @@ const char *cChannel::ToText(cChannel *Channel)
if (Channel->groupSep) if (Channel->groupSep)
asprintf(&buffer, ":%s\n", s); asprintf(&buffer, ":%s\n", s);
else { else {
char apidbuf[20]; char apidbuf[32];
char *q = apidbuf; char *q = apidbuf;
q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1); q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1);
if (Channel->apid2) if (Channel->apid2)
q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->apid2); q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->apid2);
if (Channel->dpid1 || Channel->dpid2)
q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ";%d", Channel->dpid1);
if (Channel->dpid2)
q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2);
*q = 0; *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); 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);
} }
@ -253,7 +259,13 @@ bool cChannel::Parse(const char *s)
char *apidbuf = NULL; 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); 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; apid1 = apid2 = 0;
dpid1 = dpid2 = 0;
char *p = strchr(apidbuf, ';');
if (p)
*p++ = 0;
sscanf(apidbuf, "%d,%d", &apid1, &apid2); sscanf(apidbuf, "%d,%d", &apid1, &apid2);
if (p)
sscanf(p, "%d,%d", &dpid1, &dpid2);
delete apidbuf; delete apidbuf;
if (fields >= 9) { if (fields >= 9) {
if (fields == 9) { if (fields == 9) {
@ -286,7 +298,7 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
isyslog(LOG_INFO, "switching to channel %d", number); isyslog(LOG_INFO, "switching to channel %d", number);
} }
for (int i = 3; i--;) { for (int i = 3; i--;) {
if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, tpid, ca, pnr)) if (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr))
return true; return true;
esyslog(LOG_ERR, "retrying"); esyslog(LOG_ERR, "retrying");
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.49 2001/06/16 14:05:58 kls Exp $ * $Id: config.h 1.50 2001/06/23 13:48:22 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -19,7 +19,7 @@
#include "eit.h" #include "eit.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "0.82" #define VDRVERSION "0.83"
#define MaxBuffer 10000 #define MaxBuffer 10000
@ -96,6 +96,7 @@ public:
int srate; int srate;
int vpid; int vpid;
int apid1, apid2; int apid1, apid2;
int dpid1, dpid2;
int tpid; int tpid;
int ca; int ca;
int pnr; int pnr;

129
dvbapi.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.c 1.79 2001/06/17 15:18:11 kls Exp $ * $Id: dvbapi.c 1.80 2001/06/24 17:42:19 kls Exp $
*/ */
#include "dvbapi.h" #include "dvbapi.h"
@ -451,14 +451,14 @@ protected:
virtual void Input(void); virtual void Input(void);
virtual void Output(void); virtual void Output(void);
public: public:
cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2); cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2);
virtual ~cRecordBuffer(); virtual ~cRecordBuffer();
}; };
cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2) cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cRingBuffer(VIDEOBUFSIZE, true) :cRingBuffer(VIDEOBUFSIZE, true)
,fileName(FileName, true) ,fileName(FileName, true)
,remux(VPid, APid1, APid2, true) ,remux(VPid, APid1, APid2, DPid1, DPid2, true)
{ {
dvbApi = DvbApi; dvbApi = DvbApi;
index = NULL; index = NULL;
@ -620,6 +620,7 @@ private:
cFileName fileName; cFileName fileName;
int fileOffset; int fileOffset;
int videoDev, audioDev; int videoDev, audioDev;
FILE *dolbyDev;
int replayFile; int replayFile;
bool eof; bool eof;
int blockInput, blockOutput; int blockInput, blockOutput;
@ -661,6 +662,12 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
fileOffset = 0; fileOffset = 0;
videoDev = VideoDev; videoDev = VideoDev;
audioDev = AudioDev; audioDev = AudioDev;
dolbyDev = NULL;
if (cDvbApi::AudioCommand()) {
dolbyDev = popen(cDvbApi::AudioCommand(), "w");
if (!dolbyDev)
esyslog(LOG_ERR, "ERROR: can't open pipe to audio command '%s'", cDvbApi::AudioCommand());
}
replayFile = fileName.Open(); replayFile = fileName.Open();
eof = false; eof = false;
blockInput = blockOutput = false; blockInput = blockOutput = false;
@ -688,6 +695,8 @@ cReplayBuffer::~cReplayBuffer()
Stop(); Stop();
Save(); Save();
Close(); Close();
if (dolbyDev)
pclose(dolbyDev);
dvbApi->SetModeNormal(false); dvbApi->SetModeNormal(false);
delete index; delete index;
} }
@ -795,24 +804,45 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)
for (int i = 0; i < Length - 6; i++) { for (int i = 0; i < Length - 6; i++) {
if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
uchar c = b[i + 3]; uchar c = b[i + 3];
int l = b[i + 4] * 256 + b[i + 5] + 6;
switch (c) { switch (c) {
case 0xC0 ... 0xDF: // audio case 0xBD: // dolby
{ if (Except && dolbyDev) {
int n = b[i + 4] * 256 + b[i + 5]; int written = b[i + 8] + 9; // skips the PES header
if (c == 0xC1) int n = l - written;
canToggleAudioTrack = true; while (n > 0) {
if (!Except || c != Except) { int w = fwrite(&b[i + written], 1, n, dolbyDev);
for (int j = i; j < Length && n--; j++) if (w < 0) {
b[j] = 0x00; LOG_ERROR;
} break;
i += n; }
} n -= w;
written += w;
}
}
// continue with deleting the data - otherwise it disturbs DVB replay
case 0xC0 ... 0xC1: // audio
if (c == 0xC1)
canToggleAudioTrack = true;
if (!Except || c != Except) {
int n = l;
for (int j = i; j < Length && n--; j++)
b[j] = 0x00;
}
break; break;
case 0xE0 ... 0xEF: // video case 0xE0: // video
i += b[i + 4] * 256 + b[i + 5];
break; break;
default:
//esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c);
l = 0;
} }
if (l)
i += l - 1; // the loop increments, too!
} }
/*XXX
else
esyslog(LOG_ERR, "ERROR: broken packet header");
XXX*/
} }
} }
@ -1055,14 +1085,14 @@ protected:
virtual void Input(void); virtual void Input(void);
virtual void Output(void); virtual void Output(void);
public: public:
cTransferBuffer(cDvbApi *DvbApi, int ToDevice, dvb_pid_t VPid, dvb_pid_t APid); cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid);
virtual ~cTransferBuffer(); virtual ~cTransferBuffer();
void SetAudioPid(int APid); void SetAudioPid(int APid);
}; };
cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, dvb_pid_t VPid, dvb_pid_t APid) cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid)
:cRingBuffer(VIDEOBUFSIZE, true) :cRingBuffer(VIDEOBUFSIZE, true)
,remux(VPid, APid) ,remux(VPid, APid, 0, 0, 0)
{ {
dvbApi = DvbApi; dvbApi = DvbApi;
fromDevice = dvbApi->SetModeRecord(); fromDevice = dvbApi->SetModeRecord();
@ -1336,10 +1366,11 @@ int cDvbApi::NumDvbApis = 0;
int cDvbApi::useDvbApi = 0; int cDvbApi::useDvbApi = 0;
cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL };
cDvbApi *cDvbApi::PrimaryDvbApi = NULL; cDvbApi *cDvbApi::PrimaryDvbApi = NULL;
char *cDvbApi::audioCommand = NULL;
cDvbApi::cDvbApi(int n) cDvbApi::cDvbApi(int n)
{ {
vPid = aPid1 = aPid2 = 0; vPid = aPid1 = aPid2 = dPid1 = dPid2 = 0;
siProcessor = NULL; siProcessor = NULL;
recordBuffer = NULL; recordBuffer = NULL;
replayBuffer = NULL; replayBuffer = NULL;
@ -1359,6 +1390,8 @@ cDvbApi::cDvbApi(int n)
fd_demuxv = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); fd_demuxv = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxa1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); fd_demuxa1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxa2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); fd_demuxa2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxd1 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxd2 = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
fd_demuxt = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true); fd_demuxt = OstOpen(DEV_OST_DEMUX, n, O_RDWR | O_NONBLOCK, true);
// Devices not present on "budget" cards: // Devices not present on "budget" cards:
@ -1381,7 +1414,7 @@ cDvbApi::cDvbApi(int n)
// We only check the devices that must be present - the others will be checked before accessing them: // We only check the devices that must be present - the others will be checked before accessing them:
if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxt >= 0) { if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 0 && fd_demuxd1 >= 0 && fd_demuxd2 >= 0 && fd_demuxt >= 0) {
siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n)); siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
if (!dvbApi[0]) // only the first one shall set the system time if (!dvbApi[0]) // only the first one shall set the system time
siProcessor->SetUseTSTime(Setup.SetSystemTime); siProcessor->SetUseTSTime(Setup.SetSystemTime);
@ -2037,32 +2070,35 @@ void cDvbApi::SetVideoFormat(videoFormat_t Format)
CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format)); CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format));
} }
bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Output) bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output)
{ {
if (Pid == 0x1FFF) if (Pid) {
CHECK(ioctl(fd, DMX_STOP)); CHECK(ioctl(fd, DMX_STOP));
dmxPesFilterParams pesFilterParams; dmxPesFilterParams pesFilterParams;
pesFilterParams.pid = Pid; pesFilterParams.pid = Pid;
pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.input = DMX_IN_FRONTEND;
pesFilterParams.output = Output; pesFilterParams.output = Output;
pesFilterParams.pesType = PesType; pesFilterParams.pesType = PesType;
pesFilterParams.flags = DMX_IMMEDIATE_START; pesFilterParams.flags = DMX_IMMEDIATE_START;
if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
if (Pid != 0 && Pid != 0x1FFF) if (Pid != 0x1FFF)
LOG_ERROR; LOG_ERROR;
return false; return false;
}
} }
return true; return true;
} }
bool cDvbApi::SetPids(bool ForRecording) bool cDvbApi::SetPids(bool ForRecording)
{ {
return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && return SetVpid(vPid, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) &&
SetApid1(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && SetApid1(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) &&
SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP); SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP) &&
SetDpid1(ForRecording ? dPid1 : 0, DMX_OUT_TS_TAP) &&
SetDpid2(ForRecording ? dPid2 : 0, DMX_OUT_TS_TAP);
} }
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) bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, int Dpid1, int Dpid2, int Tpid, int Ca, int Pnr)
{ {
// Make sure the siProcessor won't access the device while switching // Make sure the siProcessor won't access the device while switching
cThreadLock ThreadLock(siProcessor); cThreadLock ThreadLock(siProcessor);
@ -2084,8 +2120,14 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
SetVpid( 0x1FFF, DMX_OUT_DECODER); SetVpid( 0x1FFF, DMX_OUT_DECODER);
SetApid1(0x1FFF, DMX_OUT_DECODER); SetApid1(0x1FFF, DMX_OUT_DECODER);
SetApid2(0x1FFF, DMX_OUT_DECODER); SetApid2(0x1FFF, DMX_OUT_DECODER);
SetDpid1(0x1FFF, DMX_OUT_DECODER);
SetDpid2(0x1FFF, DMX_OUT_DECODER);
SetTpid( 0x1FFF, DMX_OUT_DECODER); SetTpid( 0x1FFF, DMX_OUT_DECODER);
// Must set this anyway to avoid getting stuck when switching through
// channels with 'Up' and 'Down' keys:
currentChannel = ChannelNumber;
bool ChannelSynced = false; bool ChannelSynced = false;
if (fd_qpskfe >= 0 && fd_sec >= 0) { // DVB-S if (fd_qpskfe >= 0 && fd_sec >= 0) { // DVB-S
@ -2188,6 +2230,8 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
vPid = Vpid; vPid = Vpid;
aPid1 = Apid1; aPid1 = Apid1;
aPid2 = Apid2; aPid2 = Apid2;
dPid1 = Dpid1;
dPid2 = Dpid2;
if (!SetPids(false)) { if (!SetPids(false)) {
esyslog(LOG_ERR, "ERROR: failed to set PIDs for channel %d", ChannelNumber); esyslog(LOG_ERR, "ERROR: failed to set PIDs for channel %d", ChannelNumber);
return false; return false;
@ -2197,7 +2241,6 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
if (this == PrimaryDvbApi && siProcessor) if (this == PrimaryDvbApi && siProcessor)
siProcessor->SetCurrentServiceID(Pnr); siProcessor->SetCurrentServiceID(Pnr);
currentChannel = ChannelNumber;
// If this DVB card can't receive this channel, let's see if we can // 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: // use the card that actually can receive it and transfer data from there:
@ -2206,7 +2249,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); cDvbApi *CaDvbApi = GetDvbApi(Ca, 0);
if (CaDvbApi) { if (CaDvbApi) {
if (!CaDvbApi->Recording()) { if (!CaDvbApi->Recording()) {
if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Tpid, Ca, Pnr)) { if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) {
SetModeReplay(); SetModeReplay();
transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video);
} }
@ -2290,7 +2333,7 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority)
// Create recording buffer: // Create recording buffer:
recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2); recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2, dPid1, dPid2);
if (recordBuffer) { if (recordBuffer) {
ca = Ca; ca = Ca;
@ -2428,6 +2471,12 @@ bool cDvbApi::ToggleAudioTrack(void)
return false; return false;
} }
void cDvbApi::SetAudioCommand(const char *Command)
{
delete audioCommand;
audioCommand = strdup(Command);
}
// --- cEITScanner ----------------------------------------------------------- // --- cEITScanner -----------------------------------------------------------
cEITScanner::cEITScanner(void) cEITScanner::cEITScanner(void)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.h 1.39 2001/06/16 14:21:16 kls Exp $ * $Id: dvbapi.h 1.40 2001/06/24 17:42:19 kls Exp $
*/ */
#ifndef __DVBAPI_H #ifndef __DVBAPI_H
@ -66,13 +66,15 @@ class cDvbApi {
friend class cTransferBuffer; friend class cTransferBuffer;
private: private:
int videoDev; int videoDev;
int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxv, fd_demuxt; int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa1, fd_demuxa2, fd_demuxd1, fd_demuxd2, fd_demuxv, fd_demuxt;
int vPid, aPid1, aPid2; int vPid, aPid1, aPid2, dPid1, dPid2;
bool SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Output); bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output);
bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); } bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO, Vpid, Output); }
bool SetApid1(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa1, DMX_PES_AUDIO, Apid, Output); } bool SetApid1(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa1, DMX_PES_AUDIO, Apid, Output); }
bool SetApid2(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa2, DMX_PES_OTHER, Apid, Output); } bool SetApid2(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa2, DMX_PES_OTHER, Apid, Output); }
bool SetTpid(int Tpid, dmxOutput_t Output) { return SetPid(fd_demuxt, DMX_PES_TELETEXT, Tpid, Output); } bool SetDpid1(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd1, DMX_PES_OTHER, Dpid, Output); }
bool SetDpid2(int Dpid, dmxOutput_t Output) { return SetPid(fd_demuxd2, DMX_PES_OTHER, Dpid, Output); }
bool SetTpid(int Tpid, dmxOutput_t Output) { return SetPid(fd_demuxt, DMX_PES_TELETEXT, Tpid, Output); }
bool SetPids(bool ForRecording); bool SetPids(bool ForRecording);
cDvbApi(int n); cDvbApi(int n);
public: public:
@ -182,7 +184,7 @@ public:
private: private:
int currentChannel; int currentChannel;
public: public:
bool SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid1, int Apid2, 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 Dpid1, int Dpid2, int Tpid, int Ca, int Pnr);
static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; }
int Channel(void) { return currentChannel; } int Channel(void) { return currentChannel; }
@ -268,11 +270,20 @@ public:
// Audio track facilities // Audio track facilities
public:
bool CanToggleAudioTrack(void); bool CanToggleAudioTrack(void);
// Returns true if we are currently replaying and this recording has two // Returns true if we are currently replaying and this recording has two
// audio tracks, or if the current channel has two audio PIDs. // audio tracks, or if the current channel has two audio PIDs.
bool ToggleAudioTrack(void); bool ToggleAudioTrack(void);
// Toggles the audio track if possible. // Toggles the audio track if possible.
// Dolby Digital audio facilities
private:
static char *audioCommand;
public:
static void SetAudioCommand(const char *Command);
static const char *AudioCommand(void) { return audioCommand; }
}; };
class cEITScanner { class cEITScanner {

16
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: i18n.c 1.20 2001/06/22 15:16:39 kls Exp $ * $Id: i18n.c 1.21 2001/06/23 13:47:15 kls Exp $
* *
* Slovenian translations provided by Miha Setina <mihasetina@softhome.net> * Slovenian translations provided by Miha Setina <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it> * Italian translations provided by Alberto Carraro <bertocar@tin.it>
@ -354,6 +354,20 @@ const tPhrase Phrases[] = {
"Apid2", "Apid2",
"Apid2", "Apid2",
}, },
{ "Dpid1",
"Dpid1",
"Dpid1",
"Dpid1",
"Dpid1",
"Dpid1",
},
{ "Dpid2",
"Dpid2",
"Dpid2",
"Dpid2",
"Dpid2",
"Dpid2",
},
{ "Tpid", { "Tpid",
"Tpid", "Tpid",
"Tpid", "Tpid",

4
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.74 2001/06/16 14:23:02 kls Exp $ * $Id: menu.c 1.75 2001/06/23 13:38:54 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -545,6 +545,8 @@ cMenuEditChannel::cMenuEditChannel(int Index)
Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0xFFFE)); Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0xFFFE));
Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0xFFFE)); Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0xFFFE));
Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0xFFFE)); Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0xFFFE));
Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0xFFFE));
Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0xFFFE));
Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 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("CA"), &data.ca, 0, cDvbApi::NumDvbApis));
Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0));

25
remux.c
View File

@ -8,7 +8,7 @@
* the Linux DVB driver's 'tuxplayer' example and were rewritten to suit * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit
* VDR's needs. * VDR's needs.
* *
* $Id: remux.c 1.4 2001/06/14 15:30:09 kls Exp $ * $Id: remux.c 1.5 2001/06/24 16:37:23 kls Exp $
*/ */
/* The calling interface of the 'cRemux::Process()' function is defined /* The calling interface of the 'cRemux::Process()' function is defined
@ -419,11 +419,13 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
// --- cRemux ---------------------------------------------------------------- // --- cRemux ----------------------------------------------------------------
cRemux::cRemux(dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2, bool ExitOnFailure) cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure)
{ {
vPid = VPid; vPid = VPid;
aPid1 = APid1; aPid1 = APid1;
aPid2 = APid2; aPid2 = APid2;
dPid1 = DPid1;
dPid2 = DPid2;
exitOnFailure = ExitOnFailure; exitOnFailure = ExitOnFailure;
synced = false; synced = false;
skipped = 0; skipped = 0;
@ -431,6 +433,9 @@ cRemux::cRemux(dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2, bool ExitOnFail
vTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS); vTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS);
aTS2PES1 = new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0); aTS2PES1 = new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0);
aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC1) : NULL; aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC1) : NULL;
dTS2PES1 = dPid1 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : NULL;
//XXX don't yet know how to tell apart primary and secondary DD data...
dTS2PES2 = /*XXX dPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS) : XXX*/ NULL;
} }
cRemux::~cRemux() cRemux::~cRemux()
@ -438,6 +443,8 @@ cRemux::~cRemux()
delete vTS2PES; delete vTS2PES;
delete aTS2PES1; delete aTS2PES1;
delete aTS2PES2; delete aTS2PES2;
delete dTS2PES1;
delete dTS2PES2;
} }
int cRemux::GetPid(const uchar *Data) int cRemux::GetPid(const uchar *Data)
@ -510,14 +517,13 @@ XXX*/
for (int i = 0; i < Count; i += TS_SIZE) { for (int i = 0; i < Count; i += TS_SIZE) {
if (Count - i < TS_SIZE) if (Count - i < TS_SIZE)
break; break;
dvb_pid_t pid = GetPid(Data + i + 1); int pid = GetPid(Data + i + 1);
if (Data[i + 3] & 0x10) { // got payload if (Data[i + 3] & 0x10) { // got payload
if (pid == vPid) if (pid == vPid) vTS2PES->ts_to_pes(Data + i);
vTS2PES->ts_to_pes(Data + i); else if (pid == aPid1) aTS2PES1->ts_to_pes(Data + i);
else if (pid == aPid1) else if (pid == aPid2 && aTS2PES2) aTS2PES2->ts_to_pes(Data + i);
aTS2PES1->ts_to_pes(Data + i); else if (pid == dPid1 && dTS2PES1) dTS2PES1->ts_to_pes(Data + i);
else if (pid == aPid2 && aTS2PES2) else if (pid == dPid2 && dTS2PES2) dTS2PES2->ts_to_pes(Data + i);
aTS2PES2->ts_to_pes(Data + i);
} }
used += TS_SIZE; used += TS_SIZE;
if (resultCount > (int)sizeof(resultBuffer) / 2) if (resultCount > (int)sizeof(resultBuffer) / 2)
@ -587,6 +593,7 @@ XXX*/
} }
} }
break; break;
case PRIVATE_STREAM1:
case AUDIO_STREAM_S ... AUDIO_STREAM_E: case AUDIO_STREAM_S ... AUDIO_STREAM_E:
{ {
int l = GetPacketLength(resultBuffer, resultCount, i); int l = GetPacketLength(resultBuffer, resultCount, i);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: remux.h 1.4 2001/06/14 15:27:07 kls Exp $ * $Id: remux.h 1.5 2001/06/23 14:06:59 kls Exp $
*/ */
#ifndef __REMUX_H #ifndef __REMUX_H
@ -32,8 +32,8 @@ private:
bool exitOnFailure; bool exitOnFailure;
bool synced; bool synced;
int skipped; int skipped;
dvb_pid_t vPid, aPid1, aPid2; int vPid, aPid1, aPid2, dPid1, dPid2;
cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2; cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2, *dTS2PES1, *dTS2PES2;
uchar resultBuffer[RESULTBUFFERSIZE]; uchar resultBuffer[RESULTBUFFERSIZE];
int resultCount; int resultCount;
int resultDelivered; int resultDelivered;
@ -41,7 +41,7 @@ private:
int GetPacketLength(const uchar *Data, int Count, int Offset); int GetPacketLength(const uchar *Data, int Count, int Offset);
int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
public: public:
cRemux(dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2 = 0, bool ExitOnFailure = false); cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure = false);
~cRemux(); ~cRemux();
void SetAudioPid(int APid); void SetAudioPid(int APid);
const uchar *Process(const uchar *Data, int &Count, int &Result, uchar *PictureType = NULL); const uchar *Process(const uchar *Data, int &Count, int &Result, uchar *PictureType = NULL);

4
runvdr
View File

@ -18,7 +18,7 @@
# See the main source file 'vdr.c' for copyright information and # See the main source file 'vdr.c' for copyright information and
# how to reach the author. # how to reach the author.
# #
# $Id: runvdr 1.6 2001/06/09 12:20:04 kls Exp $ # $Id: runvdr 1.7 2001/06/24 17:42:19 kls Exp $
DVBDIR="../DVB/driver" DVBDIR="../DVB/driver"
VDRPRG="./vdr" VDRPRG="./vdr"
@ -39,6 +39,6 @@ while (true) do
echo "restarting VDR" echo "restarting VDR"
$KILLPROC $VDRPRG $KILLPROC $VDRPRG
sleep 10 sleep 10
(cd $DVBDIR; make reload) (cd $DVBDIR; make rmmod; make insmod)
date date
done done

8
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * The project's page is at http://www.cadsoft.de/people/kls/vdr
* *
* $Id: vdr.c 1.57 2001/05/25 09:31:09 kls Exp $ * $Id: vdr.c 1.58 2001/06/23 12:29:41 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -77,6 +77,7 @@ int main(int argc, char *argv[])
char *Terminal = NULL; char *Terminal = NULL;
static struct option long_options[] = { static struct option long_options[] = {
{ "audio", required_argument, NULL, 'a' },
{ "config", required_argument, NULL, 'c' }, { "config", required_argument, NULL, 'c' },
{ "daemon", no_argument, NULL, 'd' }, { "daemon", no_argument, NULL, 'd' },
{ "device", required_argument, NULL, 'D' }, { "device", required_argument, NULL, 'D' },
@ -91,8 +92,10 @@ int main(int argc, char *argv[])
int c; int c;
int option_index = 0; int option_index = 0;
while ((c = getopt_long(argc, argv, "c:dD:hl:p:v:w:t:", long_options, &option_index)) != -1) { while ((c = getopt_long(argc, argv, "a:c:dD:hl:p:v:w:t:", long_options, &option_index)) != -1) {
switch (c) { switch (c) {
case 'a': cDvbApi::SetAudioCommand(optarg);
break;
case 'c': ConfigDirectory = optarg; case 'c': ConfigDirectory = optarg;
break; break;
case 'd': DaemonMode = true; break; case 'd': DaemonMode = true; break;
@ -107,6 +110,7 @@ int main(int argc, char *argv[])
return 2; return 2;
break; break;
case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80| case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80|
" -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n"
" -c DIR, --config=DIR read config files from DIR (default is to read them\n" " -c DIR, --config=DIR read config files from DIR (default is to read them\n"
" from the video directory)\n" " from the video directory)\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"