mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Added Dolby Digital recording/replay
This commit is contained in:
		
							
								
								
									
										5
									
								
								FORMATS
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								FORMATS
									
									
									
									
									
								
							| @@ -26,6 +26,8 @@ Video Disk Recorder File Formats | ||||
|   - Symbol rate | ||||
|   - Video PID | ||||
|   - 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 | ||||
|   - Conditional Access (0 = Free To Air, 1 = can be decrypted by the first | ||||
|     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 | ||||
|   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 | ||||
|   for audio 2 (if available). | ||||
|   for audio 2 (if available). Dolby Digital data is stored in packets with | ||||
|   ids 0xBD. | ||||
|  | ||||
|   | ||||
							
								
								
									
										5
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -526,8 +526,11 @@ Video Disk Recorder Revision History | ||||
| - New setup parameter "VideoFormat" to define the aspect ratio of the tv set | ||||
|   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. | ||||
| - 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. | ||||
|  | ||||
|   | ||||
							
								
								
									
										9
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								INSTALL
									
									
									
									
									
								
							| @@ -88,6 +88,15 @@ 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: | ||||
| ------------------------- | ||||
|  | ||||
|   | ||||
							
								
								
									
										18
									
								
								config.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								config.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: config.c 1.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" | ||||
| @@ -202,6 +202,8 @@ cChannel::cChannel(const cChannel *Channel) | ||||
|   vpid         = Channel ? Channel->vpid         : 255; | ||||
|   apid1        = Channel ? Channel->apid1        : 256; | ||||
|   apid2        = Channel ? Channel->apid2        : 0; | ||||
|   dpid1        = Channel ? Channel->dpid1        : 257; | ||||
|   dpid2        = Channel ? Channel->dpid2        : 0; | ||||
|   tpid         = Channel ? Channel->tpid         : 32; | ||||
|   ca           = Channel ? Channel->ca           : 0; | ||||
|   pnr          = Channel ? Channel->pnr          : 0; | ||||
| @@ -220,11 +222,15 @@ const char *cChannel::ToText(cChannel *Channel) | ||||
|   if (Channel->groupSep) | ||||
|      asprintf(&buffer, ":%s\n", s); | ||||
|   else { | ||||
|      char apidbuf[20]; | ||||
|      char apidbuf[32]; | ||||
|      char *q = apidbuf; | ||||
|      q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1); | ||||
|      if (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; | ||||
|      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; | ||||
|      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; | ||||
|      dpid1 = dpid2 = 0; | ||||
|      char *p = strchr(apidbuf, ';'); | ||||
|      if (p) | ||||
|         *p++ = 0; | ||||
|      sscanf(apidbuf, "%d,%d", &apid1, &apid2); | ||||
|      if (p) | ||||
|         sscanf(p, "%d,%d", &dpid1, &dpid2); | ||||
|      delete apidbuf; | ||||
|      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); | ||||
|         } | ||||
|      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; | ||||
|          esyslog(LOG_ERR, "retrying"); | ||||
|          } | ||||
|   | ||||
							
								
								
									
										5
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								config.h
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: config.h 1.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 | ||||
| @@ -19,7 +19,7 @@ | ||||
| #include "eit.h" | ||||
| #include "tools.h" | ||||
|  | ||||
| #define VDRVERSION "0.82" | ||||
| #define VDRVERSION "0.83" | ||||
|  | ||||
| #define MaxBuffer 10000 | ||||
|  | ||||
| @@ -96,6 +96,7 @@ public: | ||||
|   int srate; | ||||
|   int vpid; | ||||
|   int apid1, apid2; | ||||
|   int dpid1, dpid2; | ||||
|   int tpid; | ||||
|   int ca; | ||||
|   int pnr; | ||||
|   | ||||
							
								
								
									
										129
									
								
								dvbapi.c
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								dvbapi.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: dvbapi.c 1.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" | ||||
| @@ -451,14 +451,14 @@ protected: | ||||
|   virtual void Input(void); | ||||
|   virtual void Output(void); | ||||
| 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(); | ||||
|   }; | ||||
|  | ||||
| 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) | ||||
| ,fileName(FileName, true) | ||||
| ,remux(VPid, APid1, APid2, true) | ||||
| ,remux(VPid, APid1, APid2, DPid1, DPid2, true) | ||||
| { | ||||
|   dvbApi = DvbApi; | ||||
|   index = NULL; | ||||
| @@ -620,6 +620,7 @@ private: | ||||
|   cFileName fileName; | ||||
|   int fileOffset; | ||||
|   int videoDev, audioDev; | ||||
|   FILE *dolbyDev; | ||||
|   int replayFile; | ||||
|   bool eof; | ||||
|   int blockInput, blockOutput; | ||||
| @@ -661,6 +662,12 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const | ||||
|   fileOffset = 0; | ||||
|   videoDev = VideoDev; | ||||
|   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(); | ||||
|   eof = false; | ||||
|   blockInput = blockOutput = false; | ||||
| @@ -688,6 +695,8 @@ cReplayBuffer::~cReplayBuffer() | ||||
|   Stop(); | ||||
|   Save(); | ||||
|   Close(); | ||||
|   if (dolbyDev) | ||||
|      pclose(dolbyDev); | ||||
|   dvbApi->SetModeNormal(false); | ||||
|   delete index; | ||||
| } | ||||
| @@ -795,24 +804,45 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except) | ||||
|   for (int i = 0; i < Length - 6; i++) { | ||||
|       if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { | ||||
|          uchar c = b[i + 3]; | ||||
|          int l = b[i + 4] * 256 + b[i + 5] + 6; | ||||
|          switch (c) { | ||||
|            case 0xC0 ... 0xDF: // audio | ||||
|                 { | ||||
|                   int n = b[i + 4] * 256 + b[i + 5]; | ||||
|                   if (c == 0xC1) | ||||
|                      canToggleAudioTrack = true; | ||||
|                   if (!Except || c != Except) { | ||||
|                      for (int j = i; j < Length && n--; j++) | ||||
|                          b[j] = 0x00; | ||||
|                      } | ||||
|                   i += n; | ||||
|                 } | ||||
|            case 0xBD: // dolby | ||||
|                 if (Except && dolbyDev) { | ||||
|                    int written = b[i + 8] + 9; // skips the PES header | ||||
|                    int n = l - written; | ||||
|                    while (n > 0) { | ||||
|                          int w = fwrite(&b[i + written], 1, n, dolbyDev); | ||||
|                          if (w < 0) { | ||||
|                             LOG_ERROR; | ||||
|                             break; | ||||
|                             } | ||||
|                          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; | ||||
|            case 0xE0 ... 0xEF: // video | ||||
|                 i += b[i + 4] * 256 + b[i + 5]; | ||||
|            case 0xE0: // video | ||||
|                 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 Output(void); | ||||
| 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(); | ||||
|   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) | ||||
| ,remux(VPid, APid) | ||||
| ,remux(VPid, APid, 0, 0, 0) | ||||
| { | ||||
|   dvbApi = DvbApi; | ||||
|   fromDevice = dvbApi->SetModeRecord(); | ||||
| @@ -1336,10 +1366,11 @@ int cDvbApi::NumDvbApis = 0; | ||||
| int cDvbApi::useDvbApi = 0; | ||||
| cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; | ||||
| cDvbApi *cDvbApi::PrimaryDvbApi = NULL; | ||||
| char *cDvbApi::audioCommand = NULL; | ||||
|  | ||||
| cDvbApi::cDvbApi(int n) | ||||
| { | ||||
|   vPid = aPid1 = aPid2 = 0; | ||||
|   vPid = aPid1 = aPid2 = dPid1 = dPid2 = 0; | ||||
|   siProcessor = NULL; | ||||
|   recordBuffer = NULL; | ||||
|   replayBuffer = NULL; | ||||
| @@ -1359,6 +1390,8 @@ cDvbApi::cDvbApi(int n) | ||||
|   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_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); | ||||
|  | ||||
|   // 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: | ||||
|  | ||||
|   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)); | ||||
|      if (!dvbApi[0]) // only the first one shall set the system time | ||||
|         siProcessor->SetUseTSTime(Setup.SetSystemTime); | ||||
| @@ -2037,32 +2070,35 @@ void cDvbApi::SetVideoFormat(videoFormat_t 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)); | ||||
|   dmxPesFilterParams pesFilterParams; | ||||
|   pesFilterParams.pid     = Pid; | ||||
|   pesFilterParams.input   = DMX_IN_FRONTEND; | ||||
|   pesFilterParams.output  = Output; | ||||
|   pesFilterParams.pesType = PesType; | ||||
|   pesFilterParams.flags   = DMX_IMMEDIATE_START; | ||||
|   if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { | ||||
|      if (Pid != 0 && Pid != 0x1FFF) | ||||
|         LOG_ERROR; | ||||
|      return false; | ||||
|      dmxPesFilterParams pesFilterParams; | ||||
|      pesFilterParams.pid     = Pid; | ||||
|      pesFilterParams.input   = DMX_IN_FRONTEND; | ||||
|      pesFilterParams.output  = Output; | ||||
|      pesFilterParams.pesType = PesType; | ||||
|      pesFilterParams.flags   = DMX_IMMEDIATE_START; | ||||
|      if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { | ||||
|         if (Pid != 0x1FFF) | ||||
|            LOG_ERROR; | ||||
|         return false; | ||||
|         } | ||||
|      } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| 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) && | ||||
|          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 | ||||
|   cThreadLock ThreadLock(siProcessor); | ||||
| @@ -2084,8 +2120,14 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|   SetVpid( 0x1FFF, DMX_OUT_DECODER); | ||||
|   SetApid1(0x1FFF, DMX_OUT_DECODER); | ||||
|   SetApid2(0x1FFF, DMX_OUT_DECODER); | ||||
|   SetDpid1(0x1FFF, DMX_OUT_DECODER); | ||||
|   SetDpid2(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; | ||||
|  | ||||
|   if (fd_qpskfe >= 0 && fd_sec >= 0) { // DVB-S | ||||
| @@ -2188,6 +2230,8 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|   vPid = Vpid; | ||||
|   aPid1 = Apid1; | ||||
|   aPid2 = Apid2; | ||||
|   dPid1 = Dpid1; | ||||
|   dPid2 = Dpid2; | ||||
|   if (!SetPids(false)) { | ||||
|      esyslog(LOG_ERR, "ERROR: failed to set PIDs for channel %d", ChannelNumber); | ||||
|      return false; | ||||
| @@ -2197,7 +2241,6 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|      CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); | ||||
|   if (this == PrimaryDvbApi && siProcessor) | ||||
|      siProcessor->SetCurrentServiceID(Pnr); | ||||
|   currentChannel = ChannelNumber; | ||||
|    | ||||
|   // 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: | ||||
| @@ -2206,7 +2249,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|      cDvbApi *CaDvbApi = GetDvbApi(Ca, 0); | ||||
|      if (CaDvbApi) { | ||||
|         if (!CaDvbApi->Recording()) { | ||||
|            if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Tpid, Ca, Pnr)) { | ||||
|            if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid1, Apid2, Dpid1, Dpid2, Tpid, Ca, Pnr)) { | ||||
|               SetModeReplay(); | ||||
|               transferringFromDvbApi = CaDvbApi->StartTransfer(fd_video); | ||||
|               } | ||||
| @@ -2290,7 +2333,7 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) | ||||
|  | ||||
|   // Create recording buffer: | ||||
|  | ||||
|   recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2); | ||||
|   recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2, dPid1, dPid2); | ||||
|  | ||||
|   if (recordBuffer) { | ||||
|      ca = Ca; | ||||
| @@ -2428,6 +2471,12 @@ bool cDvbApi::ToggleAudioTrack(void) | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| void cDvbApi::SetAudioCommand(const char *Command) | ||||
| { | ||||
|   delete audioCommand; | ||||
|   audioCommand = strdup(Command); | ||||
| } | ||||
|  | ||||
| // --- cEITScanner ----------------------------------------------------------- | ||||
|  | ||||
| cEITScanner::cEITScanner(void) | ||||
|   | ||||
							
								
								
									
										25
									
								
								dvbapi.h
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								dvbapi.h
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: dvbapi.h 1.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 | ||||
| @@ -66,13 +66,15 @@ class cDvbApi { | ||||
|   friend class cTransferBuffer; | ||||
| private: | ||||
|   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 vPid, aPid1, aPid2; | ||||
|   bool SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Output); | ||||
|   bool SetVpid(int Vpid, dmxOutput_t Output) { return SetPid(fd_demuxv, DMX_PES_VIDEO,    Vpid, Output); } | ||||
|   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, dPid1, dPid2; | ||||
|   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 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 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); | ||||
|   cDvbApi(int n); | ||||
| public: | ||||
| @@ -182,7 +184,7 @@ public: | ||||
| private: | ||||
|   int currentChannel; | ||||
| 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; } | ||||
|   int Channel(void) { return currentChannel; } | ||||
|  | ||||
| @@ -268,11 +270,20 @@ public: | ||||
|  | ||||
|   // Audio track facilities | ||||
|  | ||||
| public: | ||||
|   bool CanToggleAudioTrack(void); | ||||
|        // Returns true if we are currently replaying and this recording has two | ||||
|        // audio tracks, or if the current channel has two audio PIDs. | ||||
|   bool ToggleAudioTrack(void); | ||||
|        // 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 { | ||||
|   | ||||
							
								
								
									
										16
									
								
								i18n.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								i18n.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: i18n.c 1.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> | ||||
|  * Italian   translations provided by Alberto Carraro <bertocar@tin.it> | ||||
| @@ -354,6 +354,20 @@ const tPhrase Phrases[] = { | ||||
|     "Apid2", | ||||
|     "Apid2", | ||||
|   }, | ||||
|   { "Dpid1", | ||||
|     "Dpid1", | ||||
|     "Dpid1", | ||||
|     "Dpid1", | ||||
|     "Dpid1", | ||||
|     "Dpid1", | ||||
|   }, | ||||
|   { "Dpid2", | ||||
|     "Dpid2", | ||||
|     "Dpid2", | ||||
|     "Dpid2", | ||||
|     "Dpid2", | ||||
|     "Dpid2", | ||||
|   }, | ||||
|   { "Tpid", | ||||
|     "Tpid", | ||||
|     "Tpid", | ||||
|   | ||||
							
								
								
									
										4
									
								
								menu.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								menu.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: menu.c 1.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" | ||||
| @@ -545,6 +545,8 @@ cMenuEditChannel::cMenuEditChannel(int Index) | ||||
|      Add(new cMenuEditIntItem( tr("Vpid"),         &data.vpid, 0, 0xFFFE)); | ||||
|      Add(new cMenuEditIntItem( tr("Apid1"),        &data.apid1, 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("CA"),           &data.ca, 0, cDvbApi::NumDvbApis)); | ||||
|      Add(new cMenuEditIntItem( tr("Pnr"),          &data.pnr, 0)); | ||||
|   | ||||
							
								
								
									
										25
									
								
								remux.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								remux.c
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ | ||||
|  * the Linux DVB driver's 'tuxplayer' example and were rewritten to suit | ||||
|  * VDR's needs. | ||||
|  * | ||||
|  * $Id: remux.c 1.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 | ||||
| @@ -419,11 +419,13 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188) | ||||
|  | ||||
| // --- 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; | ||||
|   aPid1 = APid1; | ||||
|   aPid2 = APid2; | ||||
|   dPid1 = DPid1; | ||||
|   dPid2 = DPid2; | ||||
|   exitOnFailure = ExitOnFailure; | ||||
|   synced = false; | ||||
|   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); | ||||
|   aTS2PES1 =         new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0); | ||||
|   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() | ||||
| @@ -438,6 +443,8 @@ cRemux::~cRemux() | ||||
|   delete vTS2PES; | ||||
|   delete aTS2PES1; | ||||
|   delete aTS2PES2; | ||||
|   delete dTS2PES1; | ||||
|   delete dTS2PES2; | ||||
| } | ||||
|  | ||||
| int cRemux::GetPid(const uchar *Data) | ||||
| @@ -510,14 +517,13 @@ XXX*/ | ||||
|   for (int i = 0; i < Count; i += TS_SIZE) { | ||||
|       if (Count - i < TS_SIZE) | ||||
|          break; | ||||
|       dvb_pid_t pid = GetPid(Data + i + 1); | ||||
|       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); | ||||
|          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); | ||||
|          } | ||||
|       used += TS_SIZE; | ||||
|       if (resultCount > (int)sizeof(resultBuffer) / 2) | ||||
| @@ -587,6 +593,7 @@ XXX*/ | ||||
|                         } | ||||
|                    } | ||||
|                    break; | ||||
|               case PRIVATE_STREAM1: | ||||
|               case AUDIO_STREAM_S ... AUDIO_STREAM_E: | ||||
|                    { | ||||
|                      int l = GetPacketLength(resultBuffer, resultCount, i); | ||||
|   | ||||
							
								
								
									
										8
									
								
								remux.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								remux.h
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: remux.h 1.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 | ||||
| @@ -32,8 +32,8 @@ private: | ||||
|   bool exitOnFailure; | ||||
|   bool synced; | ||||
|   int skipped; | ||||
|   dvb_pid_t vPid, aPid1, aPid2; | ||||
|   cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2; | ||||
|   int vPid, aPid1, aPid2, dPid1, dPid2; | ||||
|   cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2, *dTS2PES1, *dTS2PES2; | ||||
|   uchar resultBuffer[RESULTBUFFERSIZE]; | ||||
|   int resultCount; | ||||
|   int resultDelivered; | ||||
| @@ -41,7 +41,7 @@ private: | ||||
|   int GetPacketLength(const uchar *Data, int Count, int Offset); | ||||
|   int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); | ||||
| 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(); | ||||
|   void SetAudioPid(int APid); | ||||
|   const uchar *Process(const uchar *Data, int &Count, int &Result, uchar *PictureType = NULL); | ||||
|   | ||||
							
								
								
									
										4
									
								
								runvdr
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								runvdr
									
									
									
									
									
								
							| @@ -18,7 +18,7 @@ | ||||
| # See the main source file 'vdr.c' for copyright information and | ||||
| # 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" | ||||
| VDRPRG="./vdr" | ||||
| @@ -39,6 +39,6 @@ while (true) do | ||||
|       echo "restarting VDR" | ||||
|       $KILLPROC $VDRPRG | ||||
|       sleep 10 | ||||
|       (cd $DVBDIR; make reload) | ||||
|       (cd $DVBDIR; make rmmod; make insmod) | ||||
|       date | ||||
|       done | ||||
|   | ||||
							
								
								
									
										8
									
								
								vdr.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								vdr.c
									
									
									
									
									
								
							| @@ -22,7 +22,7 @@ | ||||
|  * | ||||
|  * 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> | ||||
| @@ -77,6 +77,7 @@ int main(int argc, char *argv[]) | ||||
|   char *Terminal = NULL; | ||||
|  | ||||
|   static struct option long_options[] = { | ||||
|       { "audio",    required_argument, NULL, 'a' }, | ||||
|       { "config",   required_argument, NULL, 'c' }, | ||||
|       { "daemon",   no_argument,       NULL, 'd' }, | ||||
|       { "device",   required_argument, NULL, 'D' }, | ||||
| @@ -91,8 +92,10 @@ int main(int argc, char *argv[]) | ||||
|    | ||||
|   int c; | ||||
|   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) { | ||||
|           case 'a': cDvbApi::SetAudioCommand(optarg); | ||||
|                     break; | ||||
|           case 'c': ConfigDirectory = optarg; | ||||
|                     break; | ||||
|           case 'd': DaemonMode = true; break; | ||||
| @@ -107,6 +110,7 @@ int main(int argc, char *argv[]) | ||||
|                     return 2; | ||||
|                     break; | ||||
|           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" | ||||
|                            "                           from the video directory)\n" | ||||
|                            "  -h,       --help         display this help and exit\n" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user