1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Recording and Transfer Mode now handle more than 2 audio PIDs

This commit is contained in:
Klaus Schmidinger 2005-01-16 14:40:47 +01:00
parent 9423c636a2
commit c522225344
18 changed files with 184 additions and 145 deletions

View File

@ -3311,3 +3311,10 @@ Video Disk Recorder Revision History
- Fixed playing files with PES packets longer than 2048 byte through the full
featured DVB card (thanks to Marco Kremer for reporting this one and providing
a test sample).
- Recording and Transfer Mode now handle more than 2 audio PIDs. For this the
interfaces of the following functions have been changed:
cTransferControl::cTransferControl()
cTransfer::cTransfer()
cRecorder::cRecorder()
cReceiver::cReceiver()
cRemux::cRemux()

View File

@ -14,18 +14,18 @@ Copyright &copy; 2004 Klaus Schmidinger<br>
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
</center>
<p>
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.0 are marked like this.
<!--X1.3.0--></td></tr></table>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.7 are marked like this.
<!--X1.3.7--></td></tr></table>
<!--X1.3.8--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
<!--X1.3.8--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.8 are marked like this.
<!--X1.3.8--></td></tr></table>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.18 are marked like this.
<!--X1.3.18--></td></tr></table>
<!--X1.3.19--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.19 are marked like this.
<!--X1.3.19--></td></tr></table>
<p>
VDR provides an easy to use plugin interface that allows additional functionality
to be added to the program by implementing a dynamically loadable library file.
@ -73,11 +73,9 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#Status monitor">Status monitor</a>
<li><a href="#Players">Players</a>
<li><a href="#Receivers">Receivers</a>
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<li><a href="#Filters">Filters</a>
<!--X1.3.0--></td></tr></table>
<li><a href="#The On Screen Display">The On Screen Display</a>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<li><a href="#Skins">Skins</a>
<li><a href="#Themes">Themes</a>
<!--X1.3.7--></td></tr></table>
@ -1023,7 +1021,7 @@ public:
Take a look at the files <tt>player.h</tt> and <tt>dvbplayer.c</tt> to see how VDR implements
its own player for the VDR recordings.
<p>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
To play the actual data, the player needs to call its member function
<p><table><tr><td bgcolor=#F0F0F0><pre>
@ -1046,7 +1044,7 @@ bool DevicePoll(cPoller &amp;Poller, int TimeoutMs = 0);
to determine whether the device is ready for further data.
<p>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
By default all audio track handling is done by the device a player is
attached to.
If the player can provide more than a single audio track, and has special
@ -1183,7 +1181,9 @@ public:
};
cMyReceiver::cMyReceiver(int Pid)
:cReceiver(0, -1, 1, Pid)
<!--X1.3.19--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
:cReceiver(0, -1, Pid)
<!--X1.3.19--></td></tr></table>
{
}
@ -1223,7 +1223,6 @@ Mode</i>).
If the <tt>cReceiver</tt> isn't needed any more, it may simply be <i>deleted</i>
and will automatically detach itself from the <tt>cDevice</tt>.
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<a name="Filters"><hr><h2>Filters</h2>
<center><i><b>A Fistful of Datas</b></i></center><p>
@ -1267,9 +1266,8 @@ If the <tt>cFilter</tt> isn't needed any more, it may simply be <i>deleted</i>
and will automatically detach itself from the <tt>cDevice</tt>.
<p>
See VDR/eit.c or VDR/pat.c to learn how to process filter data.
<!--X1.3.0--></td></tr></table>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<a name="The On Screen Display"><hr><h2>The On Screen Display</h2>
<center><i><b>Window to the world</b></i></center><p>
@ -1362,7 +1360,7 @@ public:
virtual cSkinDisplayMenu *DisplayMenu(void);
virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
virtual cSkinDisplayVolume *DisplayVolume(void);
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
virtual cSkinDisplayMessage *DisplayTrack(int NumTracks, const char * const *Tracks);
<!--X1.3.18--></td></tr></table>
virtual cSkinDisplayMessage *DisplayMessage(void);
@ -1384,7 +1382,7 @@ new cMySkin;
in the <a href="#Getting started"><tt>Start()</tt></a> function of your plugin.
Do not delete this object, it will be automatically deleted when the program ends.
<p>
<!--X1.3.8--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
<!--X1.3.8--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
In order to be able to easily identify plugins that implement a skin it is recommended
that the name of such a plugin should be
@ -1495,7 +1493,7 @@ repectively.
If the device can provide more than a single audio track, it can implement the
following function to make them available:
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
<p><table><tr><td bgcolor=#F0F0F0><pre>
virtual void SetAudioTrackDevice(eTrackType Type);
virtual int GetAudioChannelDevice(void);
@ -1558,7 +1556,6 @@ virtual void SetVideoFormat(bool VideoFormat16_9);
virtual void SetVolumeDevice(int Volume);
</pre></td></tr></table><p>
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<p>
<b>Section Filtering</b>
<p>
@ -1583,12 +1580,11 @@ from its constructor.
<p>
See <a href="#Filters">Filters</a> on how to set up actual filters that can
handle section data.
<!--X1.3.0--></td></tr></table>
<p>
<b>On Screen Display</b>
<p>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
If your device provides On Screen Display (OSD) capabilities (which every device
that is supposed to be used as a primary device should do), it shall implement
an "OSD provider" class, derived from <tt>cOsdProvider</tt>, which, when its <tt>CreateOsd()</tt>

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: channels.c 1.33 2004/12/26 12:34:52 kls Exp $
* $Id: channels.c 1.34 2005/01/16 13:49:30 kls Exp $
*/
#include "channels.h"
@ -193,6 +193,7 @@ cChannel::cChannel(const cChannel &Channel)
ppid = 0;
apids[0] = 0;
dpids[0] = 0;
spids[0] = 0;
tpid = 0;
caids[0] = 0;
nid = 0;
@ -421,8 +422,8 @@ void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][4], int *Dp
if (!modified)
modified = IntArraysDiffer(apids, Apids, alangs, ALangs) || IntArraysDiffer(dpids, Dpids, dlangs, DLangs);
if (modified) {
char OldApidsBuf[MAXAPIDS * 2 * 10 + 10]; // 2: Apids and Dpids, 10: 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
char NewApidsBuf[MAXAPIDS * 2 * 10 + 10];
char OldApidsBuf[(MAXAPIDS + MAXDPIDS) * 10 + 10]; // 10: 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
char NewApidsBuf[(MAXAPIDS + MAXDPIDS) * 10 + 10];
char *q = OldApidsBuf;
q += IntArrayToString(q, apids, 10, alangs);
if (dpids[0]) {
@ -443,6 +444,8 @@ void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][4], int *Dp
for (int i = 0; i <= MAXAPIDS; i++) { // <= to copy the terminating 0
apids[i] = Apids[i];
strn0cpy(alangs[i], ALangs[i], 4);
}
for (int i = 0; i <= MAXDPIDS; i++) { // <= to copy the terminating 0
dpids[i] = Dpids[i];
strn0cpy(dlangs[i], DLangs[i], 4);
}
@ -623,7 +626,7 @@ cString cChannel::ToText(const cChannel *Channel)
if (Channel->ppid && Channel->ppid != Channel->vpid)
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
*q = 0;
char apidbuf[MAXAPIDS * 2 * 10 + 10]; // 2: Apids and Dpids, 10: 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
char apidbuf[(MAXAPIDS + MAXDPIDS) * 10 + 10]; // 10: 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
q = apidbuf;
q += IntArrayToString(q, Channel->apids, 10, Channel->alangs);
if (Channel->dpids[0]) {
@ -726,7 +729,7 @@ bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
int NumDpids = 0;
char *strtok_next;
while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
if (NumDpids < MAXAPIDS) {
if (NumDpids < MAXDPIDS) {
char *l = strchr(q, '=');
if (l) {
*l++ = 0;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: channels.h 1.24 2004/12/26 12:15:52 kls Exp $
* $Id: channels.h 1.25 2005/01/16 13:46:41 kls Exp $
*/
#ifndef __CHANNELS_H
@ -30,8 +30,10 @@
#define CHANNELSMOD_AUTO 1
#define CHANNELSMOD_USER 2
#define MAXAPIDS 32
#define MAXCAIDS 8
#define MAXAPIDS 32 // audio
#define MAXDPIDS 8 // dolby
#define MAXSPIDS 8 // subtitles
#define MAXCAIDS 8 // conditional access
struct tChannelParameterMap {
int userValue;
@ -100,8 +102,10 @@ private:
int ppid;
int apids[MAXAPIDS + 1]; // list is zero-terminated
char alangs[MAXAPIDS][4];
int dpids[MAXAPIDS + 1]; // list is zero-terminated
char dlangs[MAXAPIDS][4];
int dpids[MAXDPIDS + 1]; // list is zero-terminated
char dlangs[MAXDPIDS][4];
int spids[MAXSPIDS + 1]; // list is zero-terminated
char slangs[MAXSPIDS][4];
int tpid;
int caids[MAXCAIDS + 1]; // list is zero-terminated
int nid;
@ -144,10 +148,15 @@ public:
int Srate(void) const { return srate; }
int Vpid(void) const { return vpid; }
int Ppid(void) const { return ppid; }
const int *Apids(void) const { return apids; }
const int *Dpids(void) const { return dpids; }
const int *Spids(void) const { return spids; }
int Apid(int i) const { return (0 <= i && i < MAXAPIDS) ? apids[i] : 0; }
int Dpid(int i) const { return (0 <= i && i < MAXAPIDS) ? dpids[i] : 0; }
int Dpid(int i) const { return (0 <= i && i < MAXDPIDS) ? dpids[i] : 0; }
int Spid(int i) const { return (0 <= i && i < MAXSPIDS) ? spids[i] : 0; }
const char *Alang(int i) const { return (0 <= i && i < MAXAPIDS) ? alangs[i] : ""; }
const char *Dlang(int i) const { return (0 <= i && i < MAXAPIDS) ? dlangs[i] : ""; }
const char *Dlang(int i) const { return (0 <= i && i < MAXDPIDS) ? dlangs[i] : ""; }
const char *Slang(int i) const { return (0 <= i && i < MAXSPIDS) ? slangs[i] : ""; }
int Tpid(void) const { return tpid; }
int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
int Nid(void) const { return nid; }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.c 1.73 2005/01/09 12:36:48 kls Exp $
* $Id: device.c 1.74 2005/01/16 14:05:37 kls Exp $
*/
#include "device.h"
@ -512,7 +512,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
if (CaDevice && CanReplay()) {
cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
if (CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()!
cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1)));
cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids()));
else
Result = scrNoTransfer;
}
@ -545,9 +545,10 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
// Set the available audio tracks:
ClrAvailableTracks();
currentAudioTrack = ttAudioFirst;
for (int i = 0; i < MAXAPIDS; i++) {
for (int i = 0; i < MAXAPIDS; i++)
SetAvailableTrack(ttAudio, i, Channel->Apid(i), Channel->Alang(i));
if (Setup.UseDolbyDigital)
if (Setup.UseDolbyDigital) {
for (int i = 0; i < MAXDPIDS; i++)
SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
}
// Select the preferred audio track:
@ -849,7 +850,7 @@ int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
}
if (w > 0)
Start += w;
else if (w <= 0) {
else {
if (Start != Data)
esyslog("ERROR: incomplete PES packet write!");
return Start == Data ? w : Start - Data;
@ -1041,7 +1042,7 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
cMutexLock MutexLock(&mutexReceiver);
for (int i = 0; i < MAXRECEIVERS; i++) {
if (!receiver[i]) {
for (int n = 0; n < MAXRECEIVEPIDS; n++) {
for (int n = 0; n < Receiver->numPids; n++) {
if (!AddPid(Receiver->pids[n])) {
for ( ; n-- > 0; )
DelPid(Receiver->pids[n]);
@ -1074,7 +1075,7 @@ void cDevice::Detach(cReceiver *Receiver)
receiver[i] = NULL;
Receiver->device = NULL;
Unlock();
for (int n = 0; n < MAXRECEIVEPIDS; n++)
for (int n = 0; n < Receiver->numPids; n++)
DelPid(Receiver->pids[n]);
}
else if (receiver[i])

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.h 1.51 2005/01/08 10:15:00 kls Exp $
* $Id: device.h 1.52 2005/01/16 14:26:16 kls Exp $
*/
#ifndef __DEVICE_H
@ -22,7 +22,7 @@
#include "tools.h"
#define MAXDEVICES 16 // the maximum number of devices in the system
#define MAXPIDHANDLES 16 // the maximum number of different PIDs per device
#define MAXPIDHANDLES 64 // the maximum number of different PIDs per device
#define MAXRECEIVERS 16 // the maximum number of receivers per device
#define MAXVOLUME 255
#define VOLUMEDELTA 5 // used to increase/decrease the volume
@ -59,14 +59,14 @@ enum eVideoSystem { vsPAL,
enum eTrackType { ttNone,
ttAudio,
ttAudioFirst = ttAudio,
ttAudioLast = ttAudioFirst + 31/*XXX MAXAPIDS - 1*/,
ttAudioLast = ttAudioFirst + 31, // MAXAPIDS - 1
ttDolby,
ttDolbyFirst = ttDolby,
ttDolbyLast = ttDolbyFirst + 31/*XXX MAXAPIDS - 1*/,
ttDolbyLast = ttDolbyFirst + 8, // MAXDPIDS - 1
/* future...
ttSubtitle,
ttSubtitleFirst = ttSubtitle,
ttSubtitleLast = ttSubtitleFirst + 31,
ttSubtitleLast = ttSubtitleFirst + 8, // MAXSPIDS - 1
*/
ttMaxTrackTypes
};

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbdevice.c 1.115 2005/01/16 11:59:21 kls Exp $
* $Id: dvbdevice.c 1.116 2005/01/16 12:05:13 kls Exp $
*/
#include "dvbdevice.h"
@ -813,7 +813,7 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
}
else if (StartTransferMode)
cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1)));
cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids()));
return true;
}

4
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.336 2005/01/14 14:27:29 kls Exp $
* $Id: menu.c 1.337 2005/01/16 12:05:13 kls Exp $
*/
#include "menu.h"
@ -3019,7 +3019,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
isyslog("record %s", fileName);
if (MakeDirs(fileName, true)) {
const cChannel *ch = timer->Channel();
recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apid(0), ch->Apid(1), ch->Dpid(0), ch->Dpid(1));
recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids());
if (device->AttachReceiver(recorder)) {
Recording.WriteSummary();
cStatus::MsgRecording(device, Recording.Name());

8
pat.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: pat.c 1.10 2004/10/16 10:01:12 kls Exp $
* $Id: pat.c 1.11 2005/01/16 13:54:34 kls Exp $
*/
#include "pat.h"
@ -325,9 +325,9 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
int Vpid = 0;
int Ppid = pmt.getPCRPid();
int Apids[MAXAPIDS] = { 0 };
int Dpids[MAXAPIDS] = { 0 };
int Dpids[MAXDPIDS] = { 0 };
char ALangs[MAXAPIDS][4] = { "" };
char DLangs[MAXAPIDS][4] = { "" };
char DLangs[MAXDPIDS][4] = { "" };
int Tpid = 0;
int NumApids = 0;
int NumDpids = 0;
@ -386,7 +386,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
delete d;
}
if (dpid) {
if (NumDpids < MAXAPIDS) {
if (NumDpids < MAXDPIDS) {
Dpids[NumDpids] = dpid;
strn0cpy(DLangs[NumDpids], lang, 4);
NumDpids++;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: receiver.c 1.3 2002/07/28 15:14:49 kls Exp $
* $Id: receiver.c 1.4 2005/01/16 14:03:01 kls Exp $
*/
#include <stdarg.h>
@ -12,25 +12,28 @@
#include "receiver.h"
#include "tools.h"
cReceiver::cReceiver(int Ca, int Priority, int NumPids, ...)
cReceiver::cReceiver(int Ca, int Priority, int Pid, const int *Pids1, const int *Pids2, const int *Pids3)
{
device = NULL;
ca = Ca;
priority = Priority;
for (int i = 0; i < MAXRECEIVEPIDS; i++)
pids[i] = 0;
if (NumPids) {
va_list ap;
va_start(ap, NumPids);
int n = 0;
while (n < MAXRECEIVEPIDS && NumPids--) {
if ((pids[n] = va_arg(ap, int)) != 0)
n++;
numPids = 0;
if (Pid)
pids[numPids++] = Pid;
if (Pids1) {
while (*Pids1 && numPids < MAXRECEIVEPIDS)
pids[numPids++] = *Pids1++;
}
va_end(ap);
if (Pids2) {
while (*Pids2 && numPids < MAXRECEIVEPIDS)
pids[numPids++] = *Pids2++;
}
else
esyslog("ERROR: cReceiver called without a PID!");
if (Pids3) {
while (*Pids3 && numPids < MAXRECEIVEPIDS)
pids[numPids++] = *Pids3++;
}
if (numPids >= MAXRECEIVEPIDS)
dsyslog("too many PIDs in cReceiver");
}
cReceiver::~cReceiver()
@ -41,11 +44,9 @@ cReceiver::~cReceiver()
bool cReceiver::WantsPid(int Pid)
{
if (Pid) {
for (int i = 0; i < MAXRECEIVEPIDS; i++) {
for (int i = 0; i < numPids; i++) {
if (pids[i] == Pid)
return true;
if (!pids[i])
break;
}
}
return false;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: receiver.h 1.2 2002/07/28 11:22:01 kls Exp $
* $Id: receiver.h 1.3 2005/01/16 14:05:10 kls Exp $
*/
#ifndef __RECEIVER_H
@ -12,7 +12,7 @@
#include "device.h"
#define MAXRECEIVEPIDS 16 // the maximum number of PIDs per receiver
#define MAXRECEIVEPIDS 64 // the maximum number of PIDs per receiver
class cReceiver {
friend class cDevice;
@ -21,30 +21,32 @@ private:
int ca;
int priority;
int pids[MAXRECEIVEPIDS];
int numPids;
bool WantsPid(int Pid);
protected:
void Detach(void);
virtual void Activate(bool On) {}
// This function is called just before the cReceiver gets attached to
// (On == true) or detached from (On == false) a cDevice. It can be used
// to do things like starting/stopping a thread.
// It is guaranteed that Receive() will not be called before Activate(true).
///< This function is called just before the cReceiver gets attached to
///< (On == true) or detached from (On == false) a cDevice. It can be used
///< to do things like starting/stopping a thread.
///< It is guaranteed that Receive() will not be called before Activate(true).
virtual void Receive(uchar *Data, int Length) = 0;
// This function is called from the cDevice we are attached to, and
// delivers one TS packet from the set of PIDs the cReceiver has requested.
// The data packet must be accepted immediately, and the call must return
// as soon as possible, without any unnecessary delay. Each TS packet
// will be delivered only ONCE, so the cReceiver must make sure that
// it will be able to buffer the data if necessary.
///< This function is called from the cDevice we are attached to, and
///< delivers one TS packet from the set of PIDs the cReceiver has requested.
///< The data packet must be accepted immediately, and the call must return
///< as soon as possible, without any unnecessary delay. Each TS packet
///< will be delivered only ONCE, so the cReceiver must make sure that
///< it will be able to buffer the data if necessary.
public:
cReceiver(int Ca, int Priority, int NumPids, ...);
// Creates a new receiver that requires conditional access Ca and has
// the given Priority. NumPids defines the number of PIDs that follow
// this parameter. If any of these PIDs are 0, they will be silently ignored.
// The total number of non-zero PIDs must not exceed MAXRECEIVEPIDS.
// Priority may be any value in the range 0..99. Negative values indicate
// that this cReceiver may be detached at any time (without blocking the
// cDevice it is attached to).
cReceiver(int Ca, int Priority, int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
///< Creates a new receiver that requires conditional access Ca and has
///< the given Priority. Pid is a single PID (typically the video PID), while
///< Pids1...Pids3 are pointers to zero terminated lists of PIDs.
///< If any of these PIDs are 0, they will be silently ignored.
///< The total number of non-zero PIDs must not exceed MAXRECEIVEPIDS.
///< Priority may be any value in the range 0..99. Negative values indicate
///< that this cReceiver may be detached at any time (without blocking the
///< cDevice it is attached to).
virtual ~cReceiver();
};

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recorder.c 1.12 2005/01/09 12:16:36 kls Exp $
* $Id: recorder.c 1.13 2005/01/16 12:53:17 kls Exp $
*/
#include <stdarg.h>
@ -127,8 +127,8 @@ void cFileWriter::Action(void)
active = false;
}
cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(Ca, Priority, Setup.UseDolbyDigital ? 5 : 3, VPid, APid1, APid2, DPid1, DPid2)
cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids)
:cReceiver(Ca, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids)
,cThread("recording")
{
active = false;
@ -139,7 +139,7 @@ cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int A
ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder");
ringBuffer->SetTimeouts(0, 100);
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, true);
writer = new cFileWriter(FileName, remux);
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recorder.h 1.2 2004/10/10 11:22:38 kls Exp $
* $Id: recorder.h 1.3 2005/01/16 12:05:13 kls Exp $
*/
#ifndef __RECORDER_H
@ -29,7 +29,7 @@ protected:
virtual void Receive(uchar *Data, int Length);
virtual void Action(void);
public:
cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2);
cRecorder(const char *FileName, int Ca, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids);
// Creates a new recorder that requires conditional access Ca, has
// the given Priority and will record the given PIDs into the file FileName.
virtual ~cRecorder();

73
remux.c
View File

@ -11,11 +11,12 @@
* The cDolbyRepacker code was originally written by Reinhard Nissl <rnissl@gmx.de>,
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
*
* $Id: remux.c 1.24 2005/01/15 12:07:43 kls Exp $
* $Id: remux.c 1.25 2005/01/16 14:34:25 kls Exp $
*/
#include "remux.h"
#include <stdlib.h>
#include "channels.h"
#include "thread.h"
#include "tools.h"
@ -335,6 +336,7 @@ int cDolbyRepacker::BreakAt(const uchar *Data, int Count)
class cTS2PES {
private:
int pid;
int size;
int found;
int count;
@ -362,16 +364,18 @@ private:
void write_ipack(const uint8_t *Data, int Count);
void instant_repack(const uint8_t *Buf, int Count);
public:
cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid = 0x00, cRepacker *Repacker = NULL);
cTS2PES(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid = 0x00, cRepacker *Repacker = NULL);
~cTS2PES();
int Pid(void) { return pid; }
void ts_to_pes(const uint8_t *Buf); // don't need count (=188)
void Clear(void);
};
uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 };
cTS2PES::cTS2PES(cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid, cRepacker *Repacker)
cTS2PES::cTS2PES(int Pid, cRingBufferLinear *ResultBuffer, int Size, uint8_t AudioCid, cRepacker *Repacker)
{
pid = Pid;
resultBuffer = ResultBuffer;
size = Size;
audioCid = AudioCid;
@ -700,35 +704,44 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
#define RESULTBUFFERSIZE KILOBYTE(256)
cRemux::cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure)
cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure)
{
vPid = VPid;
aPid1 = APid1;
aPid2 = APid2;
dPid1 = DPid1;
dPid2 = DPid2;
exitOnFailure = ExitOnFailure;
isRadio = VPid == 0 || VPid == 1 || VPid == 0x1FFF;
numUPTerrors = 0;
synced = false;
skipped = 0;
numTracks = 0;
resultSkipped = 0;
resultBuffer = new cRingBufferLinear(RESULTBUFFERSIZE, IPACKS, false, "Result");
resultBuffer->SetTimeouts(0, 100);
vTS2PES = new cTS2PES(resultBuffer, IPACKS);
aTS2PES1 = new cTS2PES(resultBuffer, IPACKS, 0xC0);
aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, IPACKS, 0xC1) : NULL;
dTS2PES1 = dPid1 ? new cTS2PES(resultBuffer, IPACKS, 0x00, new cDolbyRepacker) : NULL;
//XXX don't yet know how to tell apart primary and secondary DD data...
dTS2PES2 = /*XXX dPid2 ? new cTS2PES(resultBuffer, IPACKS, 0x00, new cDolbyRepacker) : XXX*/ NULL;
if (VPid)
ts2pes[numTracks++] = new cTS2PES(VPid, resultBuffer, IPACKS);
if (APids) {
int n = 0;
while (*APids && numTracks < MAXTRACKS && n < MAXAPIDS)
ts2pes[numTracks++] = new cTS2PES(*APids++, resultBuffer, IPACKS, 0xC0 + n++);
}
if (DPids) {
int n = 0;
while (*DPids && numTracks < MAXTRACKS && n < MAXDPIDS) {
ts2pes[numTracks++] = new cTS2PES(*DPids++, resultBuffer, IPACKS, 0x00, new cDolbyRepacker); //XXX substream id(n++)???
break; //XXX until we can handle substream ids we can only handle a single Dolby track
}
}
/* future...
if (SPids) {
int n = 0;
while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS)
ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS); //XXX substream id(n++)???
}
*/
}
cRemux::~cRemux()
{
delete vTS2PES;
delete aTS2PES1;
delete aTS2PES2;
delete dTS2PES1;
delete dTS2PES2;
for (int t = 0; t < numTracks; t++)
delete ts2pes[t];
delete resultBuffer;
}
@ -800,11 +813,12 @@ int cRemux::Put(const uchar *Data, int Count)
break; // A cTS2PES might write one full packet and also a small rest
int pid = GetPid(Data + i + 1);
if (Data[i + 3] & 0x10) { // got payload
if (pid == vPid) vTS2PES->ts_to_pes(Data + i);
else if (pid == aPid1) aTS2PES1->ts_to_pes(Data + i);
else if (pid == aPid2 && aTS2PES2) aTS2PES2->ts_to_pes(Data + i);
else if (pid == dPid1 && dTS2PES1) dTS2PES1->ts_to_pes(Data + i);
else if (pid == dPid2 && dTS2PES2) dTS2PES2->ts_to_pes(Data + i);
for (int t = 0; t < numTracks; t++) {
if (ts2pes[t]->Pid() == pid) {
ts2pes[t]->ts_to_pes(Data + i);
break;
}
}
}
used += TS_SIZE;
}
@ -842,7 +856,7 @@ uchar *cRemux::Get(int &Count, uchar *PictureType)
// Special VPID case to enable recording radio channels:
if (vPid == 0 || vPid == 1 || vPid == 0x1FFF) {
if (isRadio) {
// XXX actually '0' should be enough, but '1' must be used with encrypted channels (driver bug?)
// XXX also allowing 0x1FFF to not break Michael Paar's original patch,
// XXX but it would probably be best to only use '0'
@ -920,11 +934,8 @@ void cRemux::Del(int Count)
void cRemux::Clear(void)
{
if (vTS2PES) vTS2PES->Clear();
if (aTS2PES1) aTS2PES1->Clear();
if (aTS2PES2) aTS2PES2->Clear();
if (dTS2PES1) dTS2PES1->Clear();
if (dTS2PES2) dTS2PES2->Clear();
for (int t = 0; t < numTracks; t++)
ts2pes[t]->Clear();
resultBuffer->Clear();
}

16
remux.h
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.12 2004/10/15 12:31:16 kls Exp $
* $Id: remux.h 1.13 2005/01/16 13:15:17 kls Exp $
*/
#ifndef __REMUX_H
@ -21,23 +21,31 @@
#define P_FRAME 2
#define B_FRAME 3
#define MAXTRACKS 64
class cTS2PES;
class cRemux {
private:
bool exitOnFailure;
bool isRadio;
int numUPTerrors;
bool synced;
int skipped;
int vPid, aPid1, aPid2, dPid1, dPid2;
cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2, *dTS2PES1, *dTS2PES2;
cTS2PES *ts2pes[MAXTRACKS];
int numTracks;
cRingBufferLinear *resultBuffer;
int resultSkipped;
int GetPid(const uchar *Data);
int GetPacketLength(const uchar *Data, int Count, int Offset);
int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
public:
cRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, bool ExitOnFailure = false);
cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false);
///< Creates a new remuxer for the given PIDs. VPid is the video PID, while
///< APids, DPids and SPids are pointers to zero terminated lists of audio,
///< dolby and subtitle PIDs (the pointers may be NULL if there is no such
///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency
///< exit" in case of problems with the data stream.
~cRemux();
int Put(const uchar *Data, int Count);
///< Puts at most Count bytes of Data into the remuxer.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: transfer.c 1.22 2005/01/07 15:44:30 kls Exp $
* $Id: transfer.c 1.23 2005/01/16 13:26:38 kls Exp $
*/
#include "transfer.h"
@ -14,13 +14,13 @@
// --- cTransfer -------------------------------------------------------------
cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(0, -1, 5, VPid, APid1, APid2, DPid1, DPid2)
cTransfer::cTransfer(int VPid, const int *APids, const int *DPids, const int *SPids)
:cReceiver(0, -1, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids)
,cThread("transfer")
{
ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
needsBufferReserve = VPid != 0 && DPid1 != 0;
remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids);
needsBufferReserve = Setup.UseDolbyDigital && VPid != 0 && DPids && DPids[0] != 0;
active = false;
}
@ -143,8 +143,8 @@ void cTransfer::Action(void)
cDevice *cTransferControl::receiverDevice = NULL;
cTransferControl::cTransferControl(cDevice *ReceiverDevice, int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cControl(transfer = new cTransfer(VPid, APid1, APid2, DPid1, DPid2), true)
cTransferControl::cTransferControl(cDevice *ReceiverDevice, int VPid, const int *APids, const int *DPids, const int *SPids)
:cControl(transfer = new cTransfer(VPid, APids, DPids, SPids), true)
{
ReceiverDevice->AttachReceiver(transfer);
receiverDevice = ReceiverDevice;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: transfer.h 1.8 2005/01/07 15:44:32 kls Exp $
* $Id: transfer.h 1.9 2005/01/16 12:05:13 kls Exp $
*/
#ifndef __TRANSFER_H
@ -27,7 +27,7 @@ protected:
virtual void Receive(uchar *Data, int Length);
virtual void Action(void);
public:
cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2);
cTransfer(int VPid, const int *APids, const int *DPids, const int *SPids);
virtual ~cTransfer();
};
@ -36,7 +36,7 @@ private:
cTransfer *transfer;
static cDevice *receiverDevice;
public:
cTransferControl(cDevice *ReceiverDevice, int VPid, int APid1, int APid2, int DPid1, int DPid2);
cTransferControl(cDevice *ReceiverDevice, int VPid, const int *APids, const int *DPids, const int *SPids);
~cTransferControl();
virtual void Hide(void) {}
static cDevice *ReceiverDevice(void) { return receiverDevice; }

5
vdr.5
View File

@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
.\" $Id: vdr.5 1.32 2005/01/09 13:16:40 kls Exp $
.\" $Id: vdr.5 1.33 2005/01/16 13:45:57 kls Exp $
.\"
.TH vdr 5 "19 Dec 2004" "1.3.18" "Video Disk Recorder Files"
.SH NAME
@ -559,7 +559,8 @@ The files \fI001.vdr\fR...\fI255.vdr\fR are the actual recorded MPEG data
files. In order to keep the size of an individual file below a given limit,
a recording is split into several files. The contents of these files is
\fBPacketized Elementary Stream\fR (PES) and contains ES packets with ids
0xE0 for video, 0xC0 for audio 1 and 0xC1 for audio 2 (if available).
0xE0...0xEF for video (only one of these may actually occur in a file),
0xC0...0xDF for audio 1...32 (up to 32 audio tracks may occur).
Dolby Digital data is stored in packets with ids 0xBD.
.SS INDEX
The file \fIindex.vdr\fR (if present in a recording directory) contains