mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Recording both audio tracks
This commit is contained in:
		
							
								
								
									
										9
									
								
								FORMATS
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								FORMATS
									
									
									
									
									
								
							| @@ -128,3 +128,12 @@ Video Disk Recorder File Formats | ||||
|   - marks must have a frame number, and that frame MUST be an I-frame (this | ||||
|     means that only marks generated by VDR itself can be used, since they | ||||
|     will always be guaranteed to mark I-frames). | ||||
|  | ||||
| * 001.vdr ... 255.vdr | ||||
|  | ||||
|   These 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 "Packetized Elementary Stream" (PES) | ||||
|   and contains ES packets with ids 0xE0 for video, 0xC0 for audio 1 and 0xC1 | ||||
|   for audio 2 (if available). | ||||
|  | ||||
|   | ||||
							
								
								
									
										17
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -510,3 +510,20 @@ Video Disk Recorder Revision History | ||||
|  | ||||
| - Increased timeout until reporting "broken video data stream" when recording. | ||||
| - Modified method of turning off PIDs when switching channel. | ||||
| - Increased amount of non-useful data received by cRemux before assuming the | ||||
|   recording will fail. | ||||
| - If there are two audio PIDs defined for a channel, both audio tracks will | ||||
|   now be recorded and can be selectively replayed later. See the FORMATS file | ||||
|   for details on how these different audio tracks are stored in the recorded | ||||
|   files. In order for this to work properly you need to make sure that the | ||||
|   StartHWFilter() function in the driver's 'dvb.c' has | ||||
|  | ||||
|   u16 mode=0x0320; | ||||
|  | ||||
|   instead of the default | ||||
|  | ||||
|   u16 mode=0x0820; | ||||
|  | ||||
|   This will create packets for the second audio track that are small enough | ||||
|   to multiplex smoothly with the video data. | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								MANUAL
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								MANUAL
									
									
									
									
									
								
							| @@ -122,6 +122,8 @@ Video Disk Recorder User's Manual | ||||
|   to toggle between these. There can be two different audio PIDs per channel, | ||||
|   assuming that typically a channel broadcasts a country specific language | ||||
|   plus the movie's original soundtrack. | ||||
|   Recordings made form such channels will contain both audio tracks, and when | ||||
|   replaying the desired audio track can be selected the same way. | ||||
|  | ||||
| * Switching through channel groups | ||||
|  | ||||
|   | ||||
							
								
								
									
										121
									
								
								dvbapi.c
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								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.72 2001/06/14 08:19:43 kls Exp $ | ||||
|  * $Id: dvbapi.c 1.73 2001/06/14 15:10:16 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 APid); | ||||
|   cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2); | ||||
|   virtual ~cRecordBuffer(); | ||||
|   }; | ||||
|  | ||||
| cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid) | ||||
| cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2) | ||||
| :cRingBuffer(VIDEOBUFSIZE, true) | ||||
| ,fileName(FileName, true) | ||||
| ,remux(VPid, APid, true) | ||||
| ,remux(VPid, APid1, APid2, true) | ||||
| { | ||||
|   dvbApi = DvbApi; | ||||
|   index = NULL; | ||||
| @@ -608,12 +608,14 @@ private: | ||||
|   bool eof; | ||||
|   int blockInput, blockOutput; | ||||
|   bool paused, fastForward, fastRewind; | ||||
|   int lastIndex, stillIndex; | ||||
|   int lastIndex, stillIndex, playIndex; | ||||
|   bool canToggleAudioTrack; | ||||
|   uchar audioTrack; | ||||
|   bool NextFile(uchar FileNumber = 0, int FileOffset = -1); | ||||
|   void Clear(bool Block = false); | ||||
|   void Close(void); | ||||
|   int ReadFrame(uchar *b, int Length, int Max); | ||||
|   void StripAudioPackets(uchar *b, int Length); | ||||
|   void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00); | ||||
|   void DisplayFrame(uchar *b, int Length); | ||||
|   int Resume(void); | ||||
|   bool Save(void); | ||||
| @@ -631,6 +633,8 @@ public: | ||||
|   void SkipSeconds(int Seconds); | ||||
|   void Goto(int Position, bool Still = false); | ||||
|   void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); | ||||
|   bool CanToggleAudioTrack(void) { return canToggleAudioTrack; } | ||||
|   void ToggleAudioTrack(void); | ||||
|   }; | ||||
|  | ||||
| cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName) | ||||
| @@ -646,7 +650,9 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const | ||||
|   eof = false; | ||||
|   blockInput = blockOutput = false; | ||||
|   paused = fastForward = fastRewind = false; | ||||
|   lastIndex = stillIndex = -1; | ||||
|   lastIndex = stillIndex = playIndex = -1; | ||||
|   canToggleAudioTrack = false; | ||||
|   audioTrack = 0xC0; | ||||
|   if (!fileName.Name()) | ||||
|      return; | ||||
|   // Create the index file: | ||||
| @@ -701,12 +707,19 @@ void cReplayBuffer::Input(void) | ||||
|                  continue; | ||||
|                  } | ||||
|               lastIndex = Index; | ||||
|               playIndex = -1; | ||||
|               r = ReadFrame(b, Length, sizeof(b)); | ||||
|               StripAudioPackets(b, Length); | ||||
|               StripAudioPackets(b, r); | ||||
|               } | ||||
|            else { | ||||
|               lastIndex = -1; | ||||
|               r = read(replayFile, b, sizeof(b)); | ||||
|               playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset); | ||||
|               uchar FileNumber; | ||||
|               int FileOffset, Length; | ||||
|               if (!(index->Get(playIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) | ||||
|                  break; | ||||
|               r = ReadFrame(b, Length, sizeof(b)); | ||||
|               StripAudioPackets(b, r, audioTrack); | ||||
|               } | ||||
|            if (r > 0) { | ||||
|               uchar *p = b; | ||||
| @@ -778,13 +791,16 @@ int cReplayBuffer::ReadFrame(uchar *b, int Length, int Max) | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| void cReplayBuffer::StripAudioPackets(uchar *b, int Length) | ||||
| 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) { | ||||
|          switch (b[i + 3]) { | ||||
|          uchar c = b[i + 3]; | ||||
|          switch (c) { | ||||
|            case 0xC0 ... 0xDF: // audio | ||||
|                 { | ||||
|                 if (c == 0xC1) | ||||
|                    canToggleAudioTrack = true; | ||||
|                 if (!Except || c != Except) { | ||||
|                    int n = b[i + 4] * 256 + b[i + 5]; | ||||
|                    for (int j = i; j < Length && n--; j++) | ||||
|                        b[j] = 0x00; | ||||
| @@ -816,6 +832,7 @@ void cReplayBuffer::Clear(bool Block) | ||||
|            usleep(1); | ||||
|      Lock(); | ||||
|      cRingBuffer::Clear(); | ||||
|      playIndex = -1; | ||||
|      CHECK(ioctl(videoDev, VIDEO_FREEZE)); | ||||
|      CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); | ||||
|      CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); | ||||
| @@ -969,6 +986,7 @@ void cReplayBuffer::Goto(int Index, bool Still) | ||||
|      Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); | ||||
|      if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { | ||||
|         stillIndex = Index; | ||||
|         playIndex = -1; | ||||
|         uchar b[MAXFRAMESIZE]; | ||||
|         int r = ReadFrame(b, Length, sizeof(b)); | ||||
|         if (r > 0) | ||||
| @@ -977,7 +995,7 @@ void cReplayBuffer::Goto(int Index, bool Still) | ||||
|         paused = true; | ||||
|         } | ||||
|      else | ||||
|         stillIndex = -1; | ||||
|         stillIndex = playIndex = -1; | ||||
|      Clear(false); | ||||
|      } | ||||
| } | ||||
| @@ -1015,6 +1033,14 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset) | ||||
|   return replayFile >= 0; | ||||
| } | ||||
|  | ||||
| void cReplayBuffer::ToggleAudioTrack(void) | ||||
| { | ||||
|   if (CanToggleAudioTrack()) { | ||||
|      audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0; | ||||
|      Clear(); | ||||
|      } | ||||
| } | ||||
|  | ||||
| // --- cTransferBuffer ------------------------------------------------------- | ||||
|  | ||||
| class cTransferBuffer : public cRingBuffer { | ||||
| @@ -1336,7 +1362,8 @@ cDvbApi::cDvbApi(int n) | ||||
|   // Devices that all DVB cards must have: | ||||
|  | ||||
|   fd_demuxv  = OstOpen(DEV_OST_DEMUX,  n, O_RDWR | O_NONBLOCK, true); | ||||
|   fd_demuxa = 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_demuxt  = OstOpen(DEV_OST_DEMUX,  n, O_RDWR | O_NONBLOCK, true); | ||||
|  | ||||
|   // Devices not present on "budget" cards: | ||||
| @@ -1355,7 +1382,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_demuxa >= 0 && fd_demuxt >= 0) { | ||||
|   if (((fd_qpskfe >= 0 && fd_sec >= 0) || fd_qamfe >= 0) && fd_demuxv >= 0 && fd_demuxa1 >= 0 && fd_demuxa2 >= 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); | ||||
| @@ -2026,7 +2053,8 @@ bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, dvb_pid_t Pid, dmxOutput_t Ou | ||||
| bool cDvbApi::SetPids(bool ForRecording) | ||||
| { | ||||
|   return SetVpid(vPid,  ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && | ||||
|          SetApid(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER); | ||||
|          SetApid1(aPid1, ForRecording ? DMX_OUT_TS_TAP : DMX_OUT_DECODER) && | ||||
|          SetApid2(ForRecording ? aPid2 : 0, DMX_OUT_TS_TAP); | ||||
| } | ||||
|  | ||||
| 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) | ||||
| @@ -2048,9 +2076,10 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|  | ||||
|   // Turn off current PIDs: | ||||
|  | ||||
|   SetVpid(0, DMX_OUT_DECODER); | ||||
|   SetApid(0, DMX_OUT_DECODER); | ||||
|   SetTpid(0, DMX_OUT_DECODER); | ||||
|   SetVpid( 0, DMX_OUT_DECODER); | ||||
|   SetApid1(0, DMX_OUT_DECODER); | ||||
|   SetApid2(0, DMX_OUT_DECODER); | ||||
|   SetTpid( 0, DMX_OUT_DECODER); | ||||
|  | ||||
|   bool ChannelSynced = false; | ||||
|  | ||||
| @@ -2110,7 +2139,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|            esyslog(LOG_ERR, "ERROR %d in qpsk get event", res); | ||||
|         } | ||||
|      else | ||||
|         fprintf(stderr, "ERROR: timeout while tuning\n"); | ||||
|         esyslog(LOG_ERR, "ERROR: timeout while tuning\n"); | ||||
|      } | ||||
|   else if (fd_qamfe >= 0) { // DVB-C | ||||
|  | ||||
| @@ -2137,7 +2166,7 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|            esyslog(LOG_ERR, "ERROR %d in qam get event", res); | ||||
|         } | ||||
|      else | ||||
|         fprintf(stderr, "ERROR: timeout while tuning\n"); | ||||
|         esyslog(LOG_ERR, "ERROR: timeout while tuning\n"); | ||||
|      } | ||||
|   else { | ||||
|      esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device"); | ||||
| @@ -2187,28 +2216,6 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool cDvbApi::CanToggleAudioPid(void) | ||||
| { | ||||
|   return aPid1 && aPid2 && aPid1 != aPid2; | ||||
| } | ||||
|  | ||||
| bool cDvbApi::ToggleAudioPid(void) | ||||
| { | ||||
|   if (CanToggleAudioPid()) { | ||||
|      int a = aPid2; | ||||
|      aPid2 = aPid1; | ||||
|      aPid1 = a; | ||||
|      if (transferringFromDvbApi) | ||||
|         return transferringFromDvbApi->ToggleAudioPid(); | ||||
|      else { | ||||
|         if (transferBuffer) | ||||
|            transferBuffer->SetAudioPid(aPid1); | ||||
|         return SetPids(transferBuffer != NULL); | ||||
|         } | ||||
|      } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cDvbApi::Transferring(void) | ||||
| { | ||||
|   return transferBuffer; | ||||
| @@ -2278,7 +2285,7 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority) | ||||
|  | ||||
|   // Create recording buffer: | ||||
|  | ||||
|   recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1); | ||||
|   recordBuffer = new cRecordBuffer(this, FileName, vPid, aPid1, aPid2); | ||||
|  | ||||
|   if (recordBuffer) { | ||||
|      ca = Ca; | ||||
| @@ -2390,6 +2397,32 @@ void cDvbApi::Goto(int Position, bool Still) | ||||
|      replayBuffer->Goto(Position, Still); | ||||
| } | ||||
|  | ||||
| bool cDvbApi::CanToggleAudioTrack(void) | ||||
| { | ||||
|   return replayBuffer ? replayBuffer->CanToggleAudioTrack() : (aPid1 && aPid2 && aPid1 != aPid2); | ||||
| } | ||||
|  | ||||
| bool cDvbApi::ToggleAudioTrack(void) | ||||
| { | ||||
|   if (replayBuffer) { | ||||
|      replayBuffer->ToggleAudioTrack(); | ||||
|      return true; | ||||
|      } | ||||
|   else { | ||||
|      int a = aPid2; | ||||
|      aPid2 = aPid1; | ||||
|      aPid1 = a; | ||||
|      if (transferringFromDvbApi) | ||||
|         return transferringFromDvbApi->ToggleAudioTrack(); | ||||
|      else { | ||||
|         if (transferBuffer) | ||||
|            transferBuffer->SetAudioPid(aPid1); | ||||
|         return SetPids(transferBuffer != NULL); | ||||
|         } | ||||
|      } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| // --- cEITScanner ----------------------------------------------------------- | ||||
|  | ||||
| cEITScanner::cEITScanner(void) | ||||
|   | ||||
							
								
								
									
										17
									
								
								dvbapi.h
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								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.37 2001/06/03 11:51:30 kls Exp $ | ||||
|  * $Id: dvbapi.h 1.38 2001/06/14 14:54:25 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __DVBAPI_H | ||||
| @@ -66,11 +66,12 @@ class cDvbApi { | ||||
|   friend class cTransferBuffer; | ||||
| private: | ||||
|   int videoDev; | ||||
|   int fd_osd, fd_qpskfe, fd_qamfe, fd_sec, fd_dvr, fd_audio, fd_video, fd_demuxa, fd_demuxv, fd_demuxt; | ||||
|   int 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); } | ||||
|   bool SetApid(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa, DMX_PES_AUDIO,    Apid, Output); } | ||||
|   bool SetApid1(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa1, DMX_PES_AUDIO,    Apid, Output); } | ||||
|   bool SetApid2(int Apid, dmxOutput_t Output) { return SetPid(fd_demuxa2, DMX_PES_OTHER,    Apid, Output); } | ||||
|   bool SetTpid(int Tpid, dmxOutput_t Output) { return SetPid(fd_demuxt, DMX_PES_TELETEXT, Tpid, Output); } | ||||
|   bool SetPids(bool ForRecording); | ||||
|   cDvbApi(int n); | ||||
| @@ -180,8 +181,6 @@ 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); | ||||
|   static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; } | ||||
|   int Channel(void) { return currentChannel; } | ||||
|   bool CanToggleAudioPid(void); | ||||
|   bool ToggleAudioPid(void); | ||||
|  | ||||
|   // Transfer facilities | ||||
|  | ||||
| @@ -262,6 +261,14 @@ public: | ||||
|   void Goto(int Index, bool Still = false); | ||||
|        // Positions to the given index and displays that frame as a still picture | ||||
|        // if Still is true. | ||||
|  | ||||
|   // Audio track facilities | ||||
|  | ||||
|   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. | ||||
|   }; | ||||
|  | ||||
| class cEITScanner { | ||||
|   | ||||
							
								
								
									
										8
									
								
								menu.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								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.72 2001/06/02 13:51:28 kls Exp $ | ||||
|  * $Id: menu.c 1.73 2001/06/14 14:55:16 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "menu.h" | ||||
| @@ -1726,7 +1726,7 @@ cMenuMain::cMenuMain(bool Replaying) | ||||
|         } | ||||
|   if (cVideoCutter::Active()) | ||||
|      Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit)); | ||||
|   SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioPid() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); | ||||
|   SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, cReplayControl::LastReplayed() ? tr("Resume") : NULL); | ||||
|   Display(); | ||||
|   lastActivity = time(NULL); | ||||
|   SetHasHotkeys(); | ||||
| @@ -1761,9 +1761,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key) | ||||
|                case kRed:   if (!HasSubMenu()) | ||||
|                                state = osRecord; | ||||
|                             break; | ||||
|                case kGreen: if (cDvbApi::PrimaryDvbApi->CanToggleAudioPid()) { | ||||
|                case kGreen: if (cDvbApi::PrimaryDvbApi->CanToggleAudioTrack()) { | ||||
|                                Interface->Clear(); | ||||
|                                cDvbApi::PrimaryDvbApi->ToggleAudioPid(); | ||||
|                                cDvbApi::PrimaryDvbApi->ToggleAudioTrack(); | ||||
|                                state = osEnd; | ||||
|                                } | ||||
|                             break; | ||||
|   | ||||
							
								
								
									
										47
									
								
								remux.c
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								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.3 2001/06/02 15:39:16 kls Exp $ | ||||
|  * $Id: remux.c 1.4 2001/06/14 15:30:09 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| /* The calling interface of the 'cRemux::Process()' function is defined | ||||
| @@ -107,6 +107,11 @@ | ||||
|  | ||||
| #define IPACKS 2048 | ||||
|  | ||||
| // Start codes: | ||||
| #define SC_PICTURE 0x00  // "picture header" | ||||
|  | ||||
| #define MAXNONUSEFULDATA (10*1024*1024) | ||||
|  | ||||
| class cTS2PES { | ||||
| private: | ||||
|   int size; | ||||
| @@ -114,6 +119,7 @@ private: | ||||
|   int count; | ||||
|   uint8_t *buf; | ||||
|   uint8_t cid; | ||||
|   uint8_t audioCid; | ||||
|   int plength; | ||||
|   uint8_t plen[2]; | ||||
|   uint8_t flag1; | ||||
| @@ -132,7 +138,7 @@ private: | ||||
|   void write_ipack(const uint8_t *Data, int Count); | ||||
|   void instant_repack(const uint8_t *Buf, int Count); | ||||
| public: | ||||
|   cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size); | ||||
|   cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid = 0x00); | ||||
|   ~cTS2PES(); | ||||
|   void ts_to_pes(const uint8_t *Buf); // don't need count (=188) | ||||
|   void Clear(void); | ||||
| @@ -140,11 +146,12 @@ public: | ||||
|  | ||||
| uint8_t cTS2PES::headr[] = { 0x00, 0x00, 0x01 }; | ||||
|  | ||||
| cTS2PES::cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size) | ||||
| cTS2PES::cTS2PES(uint8_t *ResultBuffer, int *ResultCount, int Size, uint8_t AudioCid) | ||||
| { | ||||
|   resultBuffer = ResultBuffer; | ||||
|   resultCount = ResultCount; | ||||
|   size = Size; | ||||
|   audioCid = AudioCid; | ||||
|  | ||||
|   if (!(buf = new uint8_t[size])) | ||||
|      esyslog(LOG_ERR, "Not enough memory for ts_transform"); | ||||
| @@ -164,7 +171,10 @@ void cTS2PES::Clear(void) | ||||
|  | ||||
| void cTS2PES::store(uint8_t *Data, int Count) | ||||
| { | ||||
|   //XXX overflow check??? | ||||
|   if (*resultCount + Count > RESULTBUFFERSIZE) { | ||||
|      esyslog(LOG_ERR, "ERROR: result buffer overflow (%d + %d > %d)", *resultCount, Count, RESULTBUFFERSIZE); | ||||
|      Count = RESULTBUFFERSIZE - *resultCount; | ||||
|      } | ||||
|   memcpy(resultBuffer + *resultCount, Data, Count); | ||||
|   *resultCount += Count; | ||||
| } | ||||
| @@ -188,7 +198,7 @@ void cTS2PES::send_ipack(void) | ||||
| { | ||||
|   if (count < 10) | ||||
|      return; | ||||
|   buf[3] = cid; | ||||
|   buf[3] = (AUDIO_STREAM_S <= cid && cid <= AUDIO_STREAM_E && audioCid) ? audioCid : cid; | ||||
|   buf[4] = (uint8_t)(((count - 6) & 0xFF00) >> 8); | ||||
|   buf[5] = (uint8_t)((count - 6) & 0x00FF); | ||||
|   store(buf, count); | ||||
| @@ -409,22 +419,25 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188) | ||||
|  | ||||
| // --- cRemux ---------------------------------------------------------------- | ||||
|  | ||||
| cRemux::cRemux(dvb_pid_t VPid, dvb_pid_t APid, bool ExitOnFailure) | ||||
| cRemux::cRemux(dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2, bool ExitOnFailure) | ||||
| { | ||||
|   vPid = VPid; | ||||
|   aPid = APid; | ||||
|   aPid1 = APid1; | ||||
|   aPid2 = APid2; | ||||
|   exitOnFailure = ExitOnFailure; | ||||
|   synced = false; | ||||
|   skipped = 0; | ||||
|   resultCount = resultDelivered = 0; | ||||
|   vTS2PES  =         new cTS2PES(resultBuffer, &resultCount, IPACKS); | ||||
|   aTS2PES = new cTS2PES(resultBuffer, &resultCount, IPACKS); | ||||
|   aTS2PES1 =         new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC0); | ||||
|   aTS2PES2 = aPid2 ? new cTS2PES(resultBuffer, &resultCount, IPACKS, 0xC1) : NULL; | ||||
| } | ||||
|  | ||||
| cRemux::~cRemux() | ||||
| { | ||||
|   delete vTS2PES; | ||||
|   delete aTS2PES; | ||||
|   delete aTS2PES1; | ||||
|   delete aTS2PES2; | ||||
| } | ||||
|  | ||||
| int cRemux::GetPid(const uchar *Data) | ||||
| @@ -463,9 +476,9 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic | ||||
|  | ||||
| void cRemux::SetAudioPid(int APid) | ||||
| { | ||||
|   aPid = APid; | ||||
|   aPid1 = APid; | ||||
|   vTS2PES->Clear(); | ||||
|   aTS2PES->Clear(); | ||||
|   aTS2PES1->Clear(); | ||||
|   resultCount = resultDelivered = 0; | ||||
| } | ||||
|  | ||||
| @@ -501,8 +514,10 @@ XXX*/ | ||||
|       if (Data[i + 3] & 0x10) { // got payload | ||||
|          if (pid == vPid) | ||||
|             vTS2PES->ts_to_pes(Data + i); | ||||
|          else if (pid == aPid) | ||||
|             aTS2PES->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); | ||||
|          } | ||||
|       used += TS_SIZE; | ||||
|       if (resultCount > (int)sizeof(resultBuffer) / 2) | ||||
| @@ -520,7 +535,7 @@ XXX*/ | ||||
|   // Check if we're getting anywhere here: | ||||
|  | ||||
|   if (!synced && skipped >= 0) { | ||||
|      if (skipped > 1024*1024) { | ||||
|      if (skipped > MAXNONUSEFULDATA) { | ||||
|         esyslog(LOG_ERR, "ERROR: no useful data seen within %d byte of video stream", skipped); | ||||
|         skipped = -1; | ||||
|         if (exitOnFailure) | ||||
| @@ -538,7 +553,7 @@ XXX*/ | ||||
|      for (int i = 0; i < resultCount; i++) { | ||||
|          if (resultBuffer[i] == 0 && resultBuffer[i + 1] == 0 && resultBuffer[i + 2] == 1) { | ||||
|             switch (resultBuffer[i + 3]) { | ||||
|               case SC_VIDEO: | ||||
|               case VIDEO_STREAM_S ... VIDEO_STREAM_E: | ||||
|                    { | ||||
|                      uchar pt = NO_PICTURE; | ||||
|                      int l = ScanVideoPacket(resultBuffer, resultCount, i, pt); | ||||
| @@ -572,7 +587,7 @@ XXX*/ | ||||
|                         } | ||||
|                    } | ||||
|                    break; | ||||
|               case SC_AUDIO: | ||||
|               case AUDIO_STREAM_S ... AUDIO_STREAM_E: | ||||
|                    { | ||||
|                      int l = GetPacketLength(resultBuffer, resultCount, i); | ||||
|                      if (l < 0) | ||||
|   | ||||
							
								
								
									
										21
									
								
								remux.h
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								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.3 2001/06/02 15:15:43 kls Exp $ | ||||
|  * $Id: remux.h 1.4 2001/06/14 15:27:07 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __REMUX_H | ||||
| @@ -19,18 +19,11 @@ | ||||
| #define P_FRAME    2 | ||||
| #define B_FRAME    3 | ||||
|  | ||||
| //XXX -> remux.c??? | ||||
| // Start codes: | ||||
| #define SC_PICTURE 0x00  // "picture header" | ||||
| #define SC_SEQU    0xB3  // "sequence header" | ||||
| #define SC_PHEAD   0xBA  // "pack header" | ||||
| #define SC_SHEAD   0xBB  // "system header" | ||||
| #define SC_AUDIO   0xC0 | ||||
| #define SC_VIDEO   0xE0 | ||||
|  | ||||
| // The minimum amount of video data necessary to identify frames: | ||||
| #define MINVIDEODATA (16*1024) // just a safe guess (max. size of any frame block, plus some safety) | ||||
|  | ||||
| #define RESULTBUFFERSIZE (MINVIDEODATA * 4) | ||||
|  | ||||
| typedef unsigned char uchar; | ||||
| class cTS2PES; | ||||
|  | ||||
| @@ -39,16 +32,16 @@ private: | ||||
|   bool exitOnFailure; | ||||
|   bool synced; | ||||
|   int skipped; | ||||
|   dvb_pid_t vPid, aPid; | ||||
|   cTS2PES *vTS2PES, *aTS2PES; | ||||
|   uchar resultBuffer[MINVIDEODATA * 4];//XXX | ||||
|   dvb_pid_t vPid, aPid1, aPid2; | ||||
|   cTS2PES *vTS2PES, *aTS2PES1, *aTS2PES2; | ||||
|   uchar resultBuffer[RESULTBUFFERSIZE]; | ||||
|   int resultCount; | ||||
|   int resultDelivered; | ||||
|   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(dvb_pid_t VPid, dvb_pid_t APid, bool ExitOnFailure = false); | ||||
|   cRemux(dvb_pid_t VPid, dvb_pid_t APid1, dvb_pid_t APid2 = 0, bool ExitOnFailure = false); | ||||
|   ~cRemux(); | ||||
|   void SetAudioPid(int APid); | ||||
|   const uchar *Process(const uchar *Data, int &Count, int &Result, uchar *PictureType = NULL); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user