diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2005-01-16 14:40:47 +0100 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2005-01-16 14:40:47 +0100 |
commit | c522225344fdcbea2ec2946695d43a5dfa6c175a (patch) | |
tree | eac64a12b227614c86183257e3ea728e80986f0b | |
parent | 9423c636a25dcdc2531d51551aff33cf93abc095 (diff) | |
download | vdr-c522225344fdcbea2ec2946695d43a5dfa6c175a.tar.gz vdr-c522225344fdcbea2ec2946695d43a5dfa6c175a.tar.bz2 |
Recording and Transfer Mode now handle more than 2 audio PIDs
-rw-r--r-- | HISTORY | 7 | ||||
-rw-r--r-- | PLUGINS.html | 38 | ||||
-rw-r--r-- | channels.c | 13 | ||||
-rw-r--r-- | channels.h | 23 | ||||
-rw-r--r-- | device.c | 17 | ||||
-rw-r--r-- | device.h | 10 | ||||
-rw-r--r-- | dvbdevice.c | 4 | ||||
-rw-r--r-- | menu.c | 4 | ||||
-rw-r--r-- | pat.c | 8 | ||||
-rw-r--r-- | receiver.c | 37 | ||||
-rw-r--r-- | receiver.h | 42 | ||||
-rw-r--r-- | recorder.c | 8 | ||||
-rw-r--r-- | recorder.h | 4 | ||||
-rw-r--r-- | remux.c | 73 | ||||
-rw-r--r-- | remux.h | 16 | ||||
-rw-r--r-- | transfer.c | 14 | ||||
-rw-r--r-- | transfer.h | 6 | ||||
-rw-r--r-- | vdr.5 | 5 |
18 files changed, 184 insertions, 145 deletions
@@ -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() diff --git a/PLUGINS.html b/PLUGINS.html index 9132aa23..e8f456a6 100644 --- a/PLUGINS.html +++ b/PLUGINS.html @@ -14,18 +14,18 @@ Copyright © 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> </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> </td><td width=100%> +<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA> </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> </td><td width=100%> +<!--X1.3.8--><table width=100%><tr><td bgcolor=#00AA00> </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> </td><td width=100%> +<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000> </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> </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> </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> </td><td width=100%> +<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA> </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> </td><td width=100%> +<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000> </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 &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> </td><td width=100%> +<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000> </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> </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> </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> </td><td width=100%> +<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA> </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> </td><td width=100%> +<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000> </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> </td><td width=100%> +<!--X1.3.8--><table width=100%><tr><td bgcolor=#00AA00> </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> </td><td width=100%> +<!--X1.3.18--><table width=100%><tr><td bgcolor=#AA0000> </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> </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> </td><td width=100%> +<!--X1.3.7--><table width=100%><tr><td bgcolor=#0000AA> </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> @@ -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; @@ -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; } @@ -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,11 +545,12 @@ 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: eTrackType PreferredTrack = ttAudioFirst; int LanguagePreference = -1; @@ -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]) @@ -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 }; diff --git a/dvbdevice.c b/dvbdevice.c index 3a7d3264..e8862cb4 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -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,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()); @@ -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++; @@ -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++; - } - va_end(ap); + numPids = 0; + if (Pid) + pids[numPids++] = Pid; + if (Pids1) { + while (*Pids1 && numPids < MAXRECEIVEPIDS) + pids[numPids++] = *Pids1++; } - else - esyslog("ERROR: cReceiver called without a PID!"); + if (Pids2) { + while (*Pids2 && numPids < MAXRECEIVEPIDS) + pids[numPids++] = *Pids2++; + } + 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; @@ -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(); }; @@ -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); } @@ -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(); @@ -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(); } @@ -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. @@ -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; @@ -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; } @@ -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 |