mirror of
				https://projects.vdr-developer.org/git/vdr-plugin-streamdev.git
				synced 2023-10-10 17:16:51 +00:00 
			
		
		
		
	- added namespace to remuxers
- increased WRITERBUFSIZE - buffer was too small for high bandwidth content - removed cStreamdevStreamer::m_Running - eliminated potential busy waits in remuxers - updated cTSRemux static helpers to code of their VDR 1.6.0 counterparts - re-enabled PES vor VDR 1.7.3+. Streamdev now uses a copy of VDR 1.6.0's cRemux for TS to PES remuxing. - make sure that only complete TS packets are written to ringbuffers - use signaling instead of sleeps when writing to ringbuffers - optimized cStreamdevPatFilter PAT packet initialization - fixed cStreamdevPatFilter not processing PATs with length > TS_SIZE - 5 - use a small ringbuffer for cStreamdevPatFilter instead of writing to cStreamdevStreamers SendBuffer as two threads mustn't write to the same ringbuffer Modified Files: CONTRIBUTORS HISTORY Makefile common.c common.h streamdev-server.c libdvbmpeg/transform.h remux/extern.c remux/extern.h remux/ts2es.c remux/ts2es.h remux/ts2ps.c remux/ts2ps.h remux/tsremux.c remux/tsremux.h server/connectionHTTP.c server/connectionVTP.c server/livestreamer.c server/livestreamer.h server/menuHTTP.c server/streamer.c server/streamer.h Added Files: remux/ts2pes.c remux/ts2pes.h
This commit is contained in:
		| @@ -1,6 +1,10 @@ | ||||
| Special thanks go to the following persons (if you think your name is missing | ||||
| here, please send an email to vdrdev@schmirler.de): | ||||
|  | ||||
| Klaus Schmidinger | ||||
|   for VDR as a whole | ||||
|   for permission to use VDR 1.6.0 cRemux code for PES remuxing | ||||
|  | ||||
| Sascha Volkenandt, the original author, | ||||
|   for this great plugin | ||||
|  | ||||
| @@ -74,6 +78,7 @@ alexw | ||||
|  | ||||
| Olli Lammi | ||||
|   for fixing a busy wait when client isn't accepting data fast enough | ||||
|   for suggesting signaling instead of sleeping when writing to buffers | ||||
|  | ||||
| Joerg Pulz | ||||
|   for his FreeBSD compatibility patch | ||||
|   | ||||
							
								
								
									
										14
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -1,6 +1,20 @@ | ||||
| VDR Plugin 'streamdev' Revision History | ||||
| --------------------------------------- | ||||
|  | ||||
| - added namespace to remuxers | ||||
| - increased WRITERBUFSIZE - buffer was too small for high bandwidth content | ||||
| - removed cStreamdevStreamer::m_Running | ||||
| - eliminated potential busy waits in remuxers | ||||
| - updated cTSRemux static helpers to code of their VDR 1.6.0 counterparts | ||||
| - re-enabled PES vor VDR 1.7.3+. Streamdev now uses a copy of VDR 1.6.0's | ||||
|   cRemux for TS to PES remuxing. | ||||
| - make sure that only complete TS packets are written to ringbuffers | ||||
| - use signaling instead of sleeps when writing to ringbuffers | ||||
| - optimized cStreamdevPatFilter PAT packet initialization | ||||
| - fixed cStreamdevPatFilter not processing PATs with length > TS_SIZE - 5 | ||||
| - use a small ringbuffer for cStreamdevPatFilter instead of writing to | ||||
|   cStreamdevStreamers SendBuffer as two threads mustn't write to the same | ||||
|   ringbuffer | ||||
| - added missing call to StopSectionHandler which could cause crashes when | ||||
|   shutting down VDR | ||||
| - added IGMP based multicast streaming | ||||
|   | ||||
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| # | ||||
| # Makefile for a Video Disk Recorder plugin | ||||
| # | ||||
| # $Id: Makefile,v 1.17 2009/02/13 10:39:20 schmirl Exp $ | ||||
| # $Id: Makefile,v 1.18 2009/06/19 06:32:38 schmirl Exp $ | ||||
|  | ||||
| # The official name of this plugin. | ||||
| # This name will be used in the '-P...' option of VDR to load the plugin. | ||||
| @@ -62,7 +62,7 @@ SERVEROBJS = $(PLUGIN)-server.o \ | ||||
| 	server/connectionVTP.o server/connectionHTTP.o server/connectionIGMP.o \ | ||||
| 	server/streamer.o server/livestreamer.o server/livefilter.o \ | ||||
| 	server/suspend.o server/setup.o server/menuHTTP.o \ | ||||
| 	remux/tsremux.o remux/ts2ps.o remux/ts2es.o remux/extern.o | ||||
| 	remux/tsremux.o remux/ts2pes.o remux/ts2ps.o remux/ts2es.o remux/extern.o | ||||
| 	 | ||||
| ifdef DEBUG | ||||
| 	DEFINES += -DDEBUG | ||||
|   | ||||
							
								
								
									
										4
									
								
								common.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								common.c
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  *  $Id: common.c,v 1.9 2009/01/16 11:35:43 schmirl Exp $ | ||||
|  *  $Id: common.c,v 1.10 2009/06/19 06:32:38 schmirl Exp $ | ||||
|  */ | ||||
|   | ||||
| #include <vdr/channels.h> | ||||
| @@ -14,9 +14,7 @@ const char *VERSION = "0.5.0-pre"; | ||||
|  | ||||
| const char *StreamTypes[st_Count] = { | ||||
| 	"TS", | ||||
| #if APIVERSNUM < 10703 | ||||
| 	"PES", | ||||
| #endif | ||||
| 	"PS", | ||||
| 	"ES", | ||||
| 	"Extern", | ||||
|   | ||||
							
								
								
									
										4
									
								
								common.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								common.h
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  *  $Id: common.h,v 1.12 2009/01/16 11:35:43 schmirl Exp $ | ||||
|  *  $Id: common.h,v 1.13 2009/06/19 06:32:38 schmirl Exp $ | ||||
|  */ | ||||
|   | ||||
| #ifndef VDR_STREAMDEV_COMMON_H | ||||
| @@ -51,9 +51,7 @@ const cChannel *ChannelFromString(const char *String, int *Apid = NULL); | ||||
|  | ||||
| enum eStreamType { | ||||
| 	stTS, | ||||
| #if APIVERSNUM < 10703 | ||||
| 	stPES, | ||||
| #endif | ||||
| 	stPS, | ||||
| 	stES, | ||||
| 	stExtern, | ||||
|   | ||||
| @@ -106,7 +106,7 @@ | ||||
|  | ||||
|  | ||||
| #define MAX_PLENGTH 0xFFFF | ||||
| #define MMAX_PLENGTH (8*MAX_PLENGTH) | ||||
| #define MMAX_PLENGTH (64*MAX_PLENGTH) | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
|   | ||||
| @@ -7,6 +7,8 @@ | ||||
| #include <signal.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTSExt: public cThread { | ||||
| private: | ||||
| 	cRingBufferLinear *m_ResultBuffer; | ||||
| @@ -24,6 +26,9 @@ public: | ||||
| 	void Put(const uchar *Data, int Count); | ||||
| }; | ||||
|  | ||||
| } // namespace Streamdev | ||||
| using namespace Streamdev; | ||||
|  | ||||
| cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter): | ||||
| 		m_ResultBuffer(ResultBuffer), | ||||
| 		m_Active(false), | ||||
|   | ||||
| @@ -5,6 +5,8 @@ | ||||
| #include <vdr/ringbuffer.h> | ||||
| #include <string> | ||||
|  | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTSExt; | ||||
|  | ||||
| class cExternRemux: public cTSRemux { | ||||
| @@ -21,4 +23,6 @@ public: | ||||
| 	void Del(int Count) { m_ResultBuffer->Del(Count); } | ||||
| }; | ||||
|  | ||||
| } // namespace Streamdev | ||||
|  | ||||
| #endif // VDR_STREAMDEV_EXTERNREMUX_H | ||||
|   | ||||
| @@ -1,12 +1,13 @@ | ||||
| #include "remux/ts2es.h" | ||||
| #include "server/streamer.h" | ||||
| #include "libdvbmpeg/transform.h" | ||||
| #include "common.h" | ||||
| #include <vdr/device.h> | ||||
|  | ||||
| // from VDR's remux.c | ||||
| #define MAXNONUSEFULDATA (10*1024*1024) | ||||
|  | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTS2ES: public ipack { | ||||
| 	friend void PutES(uint8_t *Buffer, int Size, void *Data); | ||||
|  | ||||
| @@ -32,6 +33,9 @@ void PutES(uint8_t *Buffer, int Size, void *Data) | ||||
| 	This->start = 1; | ||||
| } | ||||
|  | ||||
| } // namespace Streamdev | ||||
| using namespace Streamdev; | ||||
|  | ||||
| cTS2ES::cTS2ES(cRingBufferLinear *ResultBuffer)  | ||||
| { | ||||
| 	m_ResultBuffer = ResultBuffer; | ||||
| @@ -75,10 +79,10 @@ void cTS2ES::PutTSPacket(const uint8_t *Buffer) { | ||||
|  | ||||
| cTS2ESRemux::cTS2ESRemux(int Pid): | ||||
| 		m_Pid(Pid), | ||||
| 		m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, IPACKS)), | ||||
| 		m_ResultBuffer(new cStreamdevBuffer(WRITERBUFSIZE, IPACKS)), | ||||
| 		m_Remux(new cTS2ES(m_ResultBuffer)) | ||||
| { | ||||
| 	m_ResultBuffer->SetTimeouts(0, 100); | ||||
| 	m_ResultBuffer->SetTimeouts(100, 100); | ||||
| } | ||||
|  | ||||
| cTS2ESRemux::~cTS2ESRemux()  | ||||
| @@ -111,8 +115,10 @@ int cTS2ESRemux::Put(const uchar *Data, int Count) | ||||
| 			break; | ||||
| 		if (Data[i] != TS_SYNC_BYTE) | ||||
| 			break; | ||||
| 		if (m_ResultBuffer->Free() < 2 * IPACKS) | ||||
| 		if (m_ResultBuffer->Free() < 2 * IPACKS) { | ||||
| 			m_ResultBuffer->WaitForPut(); | ||||
| 			break; // A cTS2ES might write one full packet and also a small rest | ||||
| 		} | ||||
| 		int pid = cTSRemux::GetPid(Data + i + 1); | ||||
| 		if (Data[i + 3] & 0x10) { // got payload | ||||
| 			if (m_Pid == pid) | ||||
|   | ||||
| @@ -2,15 +2,16 @@ | ||||
| #define VDR_STREAMDEV_TS2ESREMUX_H | ||||
|  | ||||
| #include "remux/tsremux.h" | ||||
| #include <vdr/ringbuffer.h> | ||||
| #include "server/streamer.h" | ||||
|  | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTS2ES; | ||||
| class cRingBufferLinear; | ||||
|  | ||||
| class cTS2ESRemux: public cTSRemux { | ||||
| private: | ||||
| 	int                m_Pid; | ||||
| 	cRingBufferLinear *m_ResultBuffer; | ||||
| 	cStreamdevBuffer  *m_ResultBuffer; | ||||
| 	cTS2ES            *m_Remux; | ||||
|  | ||||
| public: | ||||
| @@ -22,4 +23,6 @@ public: | ||||
| 	void Del(int Count) { m_ResultBuffer->Del(Count); } | ||||
| }; | ||||
|  | ||||
| } // namespace Streamdev | ||||
|  | ||||
| #endif // VDR_STREAMDEV_TS2ESREMUX_H | ||||
|   | ||||
							
								
								
									
										2035
									
								
								remux/ts2pes.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2035
									
								
								remux/ts2pes.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										58
									
								
								remux/ts2pes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								remux/ts2pes.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| /* | ||||
|  * ts2pes.h: A streaming MPEG2 remultiplexer | ||||
|  * | ||||
|  * This file is based on a copy of remux.h from Klaus Schmidinger's | ||||
|  * VDR, version 1.6.0. | ||||
|  * | ||||
|  * $Id: ts2pes.h,v 1.1 2009/06/19 06:32:40 schmirl Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef VDR_STREAMDEV_TS2PES_H | ||||
| #define VDR_STREAMDEV_TS2PES_H | ||||
|  | ||||
| #include "remux/tsremux.h" | ||||
| #include "server/streamer.h" | ||||
|  | ||||
| #define MAXTRACKS 64 | ||||
|  | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTS2PES; | ||||
|  | ||||
| class cTS2PESRemux: public cTSRemux { | ||||
| private: | ||||
|   bool noVideo; | ||||
|   bool synced; | ||||
|   int skipped; | ||||
|   Streamdev::cTS2PES *ts2pes[MAXTRACKS]; | ||||
|   int numTracks; | ||||
|   cStreamdevBuffer *resultBuffer; | ||||
|   int resultSkipped; | ||||
| public: | ||||
|   cTS2PESRemux(int VPid, const int *APids, const int *DPids, const int *SPids); | ||||
|        ///< 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). | ||||
|   ~cTS2PESRemux(); | ||||
|   int Put(const uchar *Data, int Count); | ||||
|        ///< Puts at most Count bytes of Data into the remuxer. | ||||
|        ///< \return Returns the number of bytes actually consumed from Data. | ||||
|   uchar *Get(int &Count, uchar *PictureType = NULL); | ||||
|        ///< Gets all currently available data from the remuxer. | ||||
|        ///< \return Count contains the number of bytes the result points to, and | ||||
|        ///< PictureType (if not NULL) will contain one of NO_PICTURE, I_FRAME, P_FRAME | ||||
|        ///< or B_FRAME. | ||||
|   void Del(int Count); | ||||
|        ///< Deletes Count bytes from the remuxer. Count must be the number returned | ||||
|        ///< from a previous call to Get(). Several calls to Del() with fractions of | ||||
|        ///< a previously returned Count may be made, but the total sum of all Count | ||||
|        ///< values must be exactly what the previous Get() has returned. | ||||
|   void Clear(void); | ||||
|        ///< Clears the remuxer of all data it might still contain, keeping the PID | ||||
|        ///< settings as they are. | ||||
|   }; | ||||
|  | ||||
| } // namespace Streamdev | ||||
|  | ||||
| #endif // VDR_STREAMDEV_TS2PES_H | ||||
| @@ -3,6 +3,8 @@ | ||||
| #include <vdr/channels.h> | ||||
| #include <vdr/device.h> | ||||
|  | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTS2PS { | ||||
| 	friend void PutPES(uint8_t *Buffer, int Size, void *Data); | ||||
|  | ||||
| @@ -28,6 +30,9 @@ void PutPES(uint8_t *Buffer, int Size, void *Data) | ||||
| 		esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", Size - n, Size); | ||||
| } | ||||
|  | ||||
| } // namespace Streamdev | ||||
| using namespace Streamdev; | ||||
|  | ||||
| cTS2PS::cTS2PS(cRingBufferLinear *ResultBuffer, int Pid, uint8_t AudioCid) | ||||
| { | ||||
| 	m_ResultBuffer = ResultBuffer; | ||||
| @@ -74,13 +79,13 @@ void cTS2PS::PutTSPacket(const uint8_t *Buffer) | ||||
|  | ||||
| cTS2PSRemux::cTS2PSRemux(int VPid, const int *APids, const int *DPids, const int *SPids): | ||||
| 		m_NumTracks(0), | ||||
| 		m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, IPACKS)), | ||||
| 		m_ResultBuffer(new cStreamdevBuffer(WRITERBUFSIZE, IPACKS)), | ||||
| 		m_ResultSkipped(0), | ||||
| 		m_Skipped(0), | ||||
| 		m_Synced(false), | ||||
| 		m_IsRadio(VPid == 0 || VPid == 1 || VPid == 0x1FFF) | ||||
| { | ||||
| 	m_ResultBuffer->SetTimeouts(0, 100); | ||||
| 	m_ResultBuffer->SetTimeouts(100, 100); | ||||
|  | ||||
| 	if (VPid) | ||||
| 		m_Remux[m_NumTracks++] = new cTS2PS(m_ResultBuffer, VPid); | ||||
| @@ -124,8 +129,10 @@ int cTS2PSRemux::Put(const uchar *Data, int Count) | ||||
| 			break; | ||||
| 		if (Data[i] != TS_SYNC_BYTE) | ||||
| 			break; | ||||
| 		if (m_ResultBuffer->Free() < 2 * IPACKS) | ||||
| 		if (m_ResultBuffer->Free() < 2 * IPACKS) { | ||||
| 			m_ResultBuffer->WaitForPut(); | ||||
| 			break; // A cTS2PS might write one full packet and also a small rest | ||||
| 		} | ||||
| 		int pid = GetPid(Data + i + 1); | ||||
| 		if (Data[i + 3] & 0x10) { // got payload | ||||
| 			for (int t = 0; t < m_NumTracks; t++) { | ||||
|   | ||||
| @@ -2,20 +2,21 @@ | ||||
| #define VDR_STREAMDEV_TS2PESREMUX_H | ||||
|  | ||||
| #include "remux/tsremux.h" | ||||
| #include <vdr/remux.h> | ||||
| #include <vdr/ringbuffer.h> | ||||
| #include "server/streamer.h" | ||||
|  | ||||
| #ifndef MAXTRACKS | ||||
| #define MAXTRACKS 64 | ||||
| #endif | ||||
|  | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTS2PS; | ||||
|  | ||||
| class cTS2PSRemux: public cTSRemux { | ||||
| private: | ||||
| 	int                m_NumTracks; | ||||
| 	cTS2PS            *m_Remux[MAXTRACKS]; | ||||
| 	cRingBufferLinear *m_ResultBuffer; | ||||
| 	cStreamdevBuffer  *m_ResultBuffer; | ||||
| 	int                m_ResultSkipped; | ||||
| 	int                m_Skipped; | ||||
| 	bool               m_Synced; | ||||
| @@ -30,4 +31,6 @@ public: | ||||
| 	void Del(int Count) { m_ResultBuffer->Del(Count); } | ||||
| }; | ||||
|  | ||||
| } // namespace Streamdev | ||||
|  | ||||
| #endif // VDR_STREAMDEV_TS2PESREMUX_H | ||||
|   | ||||
| @@ -2,11 +2,15 @@ | ||||
|  | ||||
| #define SC_PICTURE  0x00  // "picture header" | ||||
| #define PID_MASK_HI 0x1F | ||||
| #define VIDEO_STREAM_S   0xE0 | ||||
|  | ||||
| using namespace Streamdev; | ||||
|  | ||||
| void cTSRemux::SetBrokenLink(uchar *Data, int Length) | ||||
| { | ||||
|   if (Length > 9 && Data[0] == 0 && Data[1] == 0 && Data[2] == 1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) { | ||||
|      for (int i = Data[8] + 9; i < Length - 7; i++) { // +9 to skip video packet header | ||||
|   int PesPayloadOffset = 0; | ||||
|   if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) { | ||||
|      for (int i = PesPayloadOffset; i < Length - 7; i++) { | ||||
|          if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) { | ||||
|             if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed | ||||
|                Data[i + 7] |= 0x20; | ||||
| @@ -40,17 +44,40 @@ int cTSRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &P | ||||
|   // If the return value is -1 the packet was not completely in the buffer. | ||||
|   int Length = GetPacketLength(Data, Count, Offset); | ||||
|   if (Length > 0) { | ||||
|      if (Length >= 8) { | ||||
|         int i = Offset + 8; // the minimum length of the video packet header | ||||
|         i += Data[i] + 1;   // possible additional header bytes | ||||
|         for (; i < Offset + Length - 5; i++) { | ||||
|             if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) { | ||||
|                switch (Data[i + 3]) { | ||||
|                  case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07; | ||||
|                                   return Length; | ||||
|      int PesPayloadOffset = 0; | ||||
|      if (AnalyzePesHeader(Data + Offset, Length, PesPayloadOffset) >= phMPEG1) { | ||||
|         const uchar *p = Data + Offset + PesPayloadOffset + 2; | ||||
|         const uchar *pLimit = Data + Offset + Length - 3; | ||||
| #ifdef TEST_cVideoRepacker | ||||
|         // cVideoRepacker ensures that a new PES packet is started for a new sequence, | ||||
|         // group or picture which allows us to easily skip scanning through a huge | ||||
|         // amount of video data. | ||||
|         if (p < pLimit) { | ||||
|            if (p[-2] || p[-1] || p[0] != 0x01) | ||||
|               pLimit = 0; // skip scanning: packet doesn't start with 0x000001 | ||||
|            else { | ||||
|               switch (p[1]) { | ||||
|                 case SC_SEQUENCE: | ||||
|                 case SC_GROUP: | ||||
|                 case SC_PICTURE: | ||||
|                      break; | ||||
|                 default: // skip scanning: packet doesn't start a new sequence, group or picture | ||||
|                      pLimit = 0; | ||||
|                 } | ||||
|               } | ||||
|            } | ||||
| #endif | ||||
|         while (p < pLimit && (p = (const uchar *)memchr(p, 0x01, pLimit - p))) { | ||||
|               if (!p[-2] && !p[-1]) { // found 0x000001 | ||||
|                  switch (p[1]) { | ||||
|                    case SC_PICTURE: PictureType = (p[3] >> 3) & 0x07; | ||||
|                                     return Length; | ||||
|                    } | ||||
|                  p += 4; // continue scanning after 0x01ssxxyy | ||||
|                  } | ||||
|                } | ||||
|             } | ||||
|               else | ||||
|                  p += 3; // continue scanning after 0x01xxyy | ||||
|               } | ||||
|         } | ||||
|      PictureType = NO_PICTURE; | ||||
|      return Length; | ||||
|   | ||||
| @@ -4,34 +4,22 @@ | ||||
| #include "libdvbmpeg/transform.h" | ||||
| #include <vdr/remux.h> | ||||
|  | ||||
| #ifndef NO_PICTURE | ||||
| // Picture types: | ||||
| #define NO_PICTURE 0 | ||||
| #endif | ||||
| #define I_FRAME    1 | ||||
| #define P_FRAME    2 | ||||
| #define B_FRAME    3 | ||||
|  | ||||
| #define RESULTBUFFERSIZE KILOBYTE(256) | ||||
| namespace Streamdev { | ||||
|  | ||||
| class cTSRemux { | ||||
| protected: | ||||
|   /*uchar m_ResultBuffer[RESULTBUFFERSIZE]; | ||||
| 	int m_ResultCount; | ||||
| 	int m_ResultDelivered; | ||||
| 	int m_Synced; | ||||
| 	int m_Skipped; | ||||
| 	int m_Sync; | ||||
|  | ||||
|  | ||||
| 	virtual void PutTSPacket(int Pid, const uint8_t *Data) = 0; | ||||
|  | ||||
| public: | ||||
| 	cTSRemux(bool Sync = true); | ||||
| 	virtual ~cTSRemux(); | ||||
| 	 | ||||
| 	virtual uchar *Process(const uchar *Data, int &Count, int &Result);*/ | ||||
|  | ||||
| 	static void SetBrokenLink(uchar *Data, int Length); | ||||
| 	static int GetPid(const uchar *Data); | ||||
|  	static int GetPacketLength(const uchar *Data, int Count, int Offset); | ||||
| 	static int GetPacketLength(const uchar *Data, int Count, int Offset); | ||||
| 	static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType); | ||||
| }; | ||||
|  | ||||
| } // namespace Streamdev | ||||
|  | ||||
| #endif // VDR_STREAMDEV_TSREMUX_H | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  *  $Id: connectionHTTP.c,v 1.16 2009/02/13 07:02:19 schmirl Exp $ | ||||
|  *  $Id: connectionHTTP.c,v 1.17 2009/06/19 06:32:45 schmirl Exp $ | ||||
|  */ | ||||
|  | ||||
| #include <ctype.h> | ||||
| @@ -211,10 +211,8 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts) | ||||
| 	const char* pType = type.c_str(); | ||||
| 	if (strcasecmp(pType, "PS") == 0) { | ||||
| 		m_StreamType = stPS; | ||||
| #if APIVERSNUM < 10703 | ||||
| 	} else if (strcasecmp(pType, "PES") == 0) { | ||||
| 		m_StreamType = stPES; | ||||
| #endif | ||||
| 	} else if (strcasecmp(pType, "TS") == 0) { | ||||
| 		m_StreamType = stTS; | ||||
| 	} else if (strcasecmp(pType, "ES") == 0) { | ||||
| @@ -266,9 +264,7 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts) | ||||
| 				{ | ||||
| 					case stTS:	base += "TS/"; break; | ||||
| 					case stPS:	base += "PS/"; break; | ||||
| #if APIVERSNUM < 10703 | ||||
| 					case stPES:	base += "PES/"; break; | ||||
| #endif | ||||
| 					case stES:	base += "ES/"; break; | ||||
| 					case stExtern:	base += "Extern/"; break; | ||||
| 					default:	break; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  *  $Id: connectionVTP.c,v 1.19 2009/01/16 11:35:44 schmirl Exp $ | ||||
|  *  $Id: connectionVTP.c,v 1.20 2009/06/19 06:32:45 schmirl Exp $ | ||||
|  */ | ||||
|   | ||||
| #include "server/connectionVTP.h" | ||||
| @@ -595,12 +595,10 @@ bool cConnectionVTP::CmdCAPS(char *Opts) | ||||
| 		return Respond(220, "Capability \"%s\" accepted", Opts); | ||||
| 	} | ||||
|  | ||||
| #if APIVERSNUM < 10703 | ||||
| 	if (strcasecmp(Opts, "PES") == 0) { | ||||
| 		m_StreamType = stPES; | ||||
| 		return Respond(220, "Capability \"%s\" accepted", Opts); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	if (strcasecmp(Opts, "EXTERN") == 0) { | ||||
| 		m_StreamType = stExtern; | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include <libsi/descriptor.h> | ||||
|  | ||||
| #include "remux/ts2ps.h" | ||||
| #include "remux/ts2pes.h" | ||||
| #include "remux/ts2es.h" | ||||
| #include "remux/extern.h" | ||||
|  | ||||
| @@ -13,7 +14,7 @@ | ||||
| #include "server/livefilter.h" | ||||
| #include "common.h" | ||||
|  | ||||
| #define TSPATREPACKER | ||||
| using namespace Streamdev; | ||||
|  | ||||
| // --- cStreamdevLiveReceiver ------------------------------------------------- | ||||
|  | ||||
| @@ -64,6 +65,8 @@ private: | ||||
| 	int    pmtPid; | ||||
| 	int    pmtSid; | ||||
| 	int    pmtVersion; | ||||
| 	uchar  tspat_buf[TS_SIZE]; | ||||
| 	cStreamdevBuffer siBuffer; | ||||
|  | ||||
| 	const cChannel *m_Channel; | ||||
| 	cStreamdevLiveStreamer *m_Streamer; | ||||
| @@ -73,9 +76,11 @@ private: | ||||
| 	int GetPid(SI::PMT::Stream& stream); | ||||
| public: | ||||
| 	cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel); | ||||
| 	uchar* Get(int &Count) { return siBuffer.Get(Count); } | ||||
| 	void Del(int Count) { return siBuffer.Del(Count); } | ||||
| }; | ||||
|  | ||||
| cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel) | ||||
| cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel): siBuffer(10 * TS_SIZE, TS_SIZE) | ||||
| { | ||||
| 	Dprintf("cStreamdevPatFilter(\"%s\")\n", Channel->Name()); | ||||
| 	assert(Streamer); | ||||
| @@ -85,6 +90,29 @@ cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const | ||||
| 	pmtSid = 0; | ||||
| 	pmtVersion = -1; | ||||
| 	Set(0x00, 0x00);  // PAT | ||||
| 	// initialize PAT buffer. Only some values are dynamic (see comments) | ||||
| 	memset(tspat_buf, 0xff, TS_SIZE); | ||||
| 	tspat_buf[0] = TS_SYNC_BYTE;          // Transport packet header sunchronization byte (1000011 = 0x47h) | ||||
| 	tspat_buf[1] = 0x40;                  // Set payload unit start indicator bit | ||||
| 	tspat_buf[2] = 0x0;                   // PID | ||||
| 	tspat_buf[3] = 0x10;                  // Set payload flag, DYNAMIC: Continuity counter | ||||
| 	tspat_buf[4] = 0x0;                   // SI pointer field | ||||
| 	tspat_buf[5] = 0x0;                   // PAT table id | ||||
| 	tspat_buf[6] = 0xb0;                  // Section syntax indicator bit and reserved bits set | ||||
| 	tspat_buf[7] = 12 + 1;                // Section length (12 bit): PAT_TABLE_LEN + 1 | ||||
| 	tspat_buf[8] = 0;                     // DYNAMIC: Transport stream ID (bits 8-15) | ||||
| 	tspat_buf[9] = 0;                     // DYNAMIC: Transport stream ID (bits 0-7) | ||||
| 	tspat_buf[10] = 0xc0;                 // Reserved, DYNAMIC: Version number, DYNAMIC: Current next indicator | ||||
| 	tspat_buf[11] = 0x0;                  // Section number | ||||
| 	tspat_buf[12] = 0x0;                  // Last section number | ||||
| 	tspat_buf[13] = 0;                    // DYNAMIC: Program number (bits 8-15) | ||||
| 	tspat_buf[14] = 0;                    // DYNAMIC: Program number (bits 0-7) | ||||
| 	tspat_buf[15] = 0xe0;                 // Reserved, DYNAMIC: Network ID (bits 8-12) | ||||
| 	tspat_buf[16] = 0;                    // DYNAMIC: Network ID (bits 0-7) | ||||
| 	tspat_buf[17] = 0;                    // DYNAMIC: Checksum | ||||
| 	tspat_buf[18] = 0;                    // DYNAMIC: Checksum | ||||
| 	tspat_buf[19] = 0;                    // DYNAMIC: Checksum | ||||
| 	tspat_buf[20] = 0;                    // DYNAMIC: Checksum | ||||
| } | ||||
|  | ||||
| static const char * const psStreamTypes[] = { | ||||
| @@ -224,54 +252,37 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i | ||||
| 						if (0 != (pmtPid = assoc.getPid())) { | ||||
| 							Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d\n", Channel->Name(), pmtPid); | ||||
| 							pmtSid = assoc.getServiceId(); | ||||
| 							if (Length < TS_SIZE-5) { | ||||
| 								// repack PAT to TS frame and send to client | ||||
| #ifndef TSPATREPACKER | ||||
| 								uint8_t pat_ts[TS_SIZE] = {TS_SYNC_BYTE, 0x40 /* pusi=1 */, 0 /* pid=0 */, 0x10 /* adaption=1 */, 0 /* pointer */}; | ||||
| 								memcpy(pat_ts + 5, Data, Length); | ||||
| 								m_Streamer->Put(pat_ts, TS_SIZE); | ||||
| #else | ||||
| 								int ts_id; | ||||
| 								unsigned int crc, i, len; | ||||
| 								uint8_t *tmp, tspat_buf[TS_SIZE]; | ||||
| 								static uint8_t ccounter = 0; | ||||
| 								ccounter = (ccounter + 1) % 16; | ||||
| 								memset(tspat_buf, 0xff, TS_SIZE); | ||||
| 								ts_id = Channel->Tid();               // Get transport stream id of the channel | ||||
| 								tspat_buf[0] = TS_SYNC_BYTE;          // Transport packet header sunchronization byte (1000011 = 0x47h) | ||||
| 								tspat_buf[1] = 0x40;                  // Set payload unit start indicator bit | ||||
| 								tspat_buf[2] = 0x0;                   // PID | ||||
| 								tspat_buf[3] = 0x10 | ccounter;       // Set payload flag, Continuity counter | ||||
| 								tspat_buf[4] = 0x0;                   // SI pointer field | ||||
| 								tspat_buf[5] = 0x0;                   // PAT table id | ||||
| 								tspat_buf[6] = 0xb0;                  // Section syntax indicator bit and reserved bits set | ||||
| 								tspat_buf[7] = 12 + 1;                // Section length (12 bit): PAT_TABLE_LEN + 1 | ||||
| 								tspat_buf[8] = (ts_id >> 8);          // Transport stream ID (bits 8-15) | ||||
| 								tspat_buf[9] = (ts_id & 0xff);        // Transport stream ID (bits 0-7) | ||||
| 								tspat_buf[10] = 0xc0 | ((pat.getVersionNumber() << 1) & 0x3e) | | ||||
| 									pat.getCurrentNextIndicator();// Version number, Current next indicator | ||||
| 								tspat_buf[11] = 0x0;                  // Section number | ||||
| 								tspat_buf[12] = 0x0;                  // Last section number | ||||
| 								tspat_buf[13] = (pmtSid >> 8);        // Program number (bits 8-15) | ||||
| 								tspat_buf[14] = (pmtSid & 0xff);      // Program number (bits 0-7) | ||||
| 								tspat_buf[15] = 0xe0 | (pmtPid >> 8); // Network ID (bits 8-12) | ||||
| 								tspat_buf[16] = (pmtPid & 0xff);      // Network ID (bits 0-7) | ||||
| 								crc = 0xffffffff; | ||||
| 								len = 12;                             // PAT_TABLE_LEN | ||||
| 								tmp = &tspat_buf[4 + 1];              // TS_HDR_LEN + 1 | ||||
| 								while (len--) { | ||||
| 									crc ^= *tmp++ << 24; | ||||
| 									for (i = 0; i < 8; i++) | ||||
| 										crc = (crc << 1) ^ ((crc & 0x80000000) ? 0x04c11db7 : 0); // CRC32POLY | ||||
| 								} | ||||
| 								tspat_buf[17] = crc >> 24 & 0xff;     // Checksum | ||||
| 								tspat_buf[18] = crc >> 16 & 0xff;     // Checksum | ||||
| 								tspat_buf[19] = crc >>  8 & 0xff;     // Checksum | ||||
| 								tspat_buf[20] = crc & 0xff;           // Checksum | ||||
| 								m_Streamer->Put(tspat_buf, TS_SIZE); | ||||
| #endif | ||||
| 							} else  | ||||
| 								isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length); | ||||
| 							// repack PAT to TS frame and send to client | ||||
| 							int ts_id; | ||||
| 							unsigned int crc, i, len; | ||||
| 							uint8_t *tmp; | ||||
| 							static uint8_t ccounter = 0; | ||||
| 							ccounter = (ccounter + 1) % 16; | ||||
| 							ts_id = Channel->Tid();               // Get transport stream id of the channel | ||||
| 							tspat_buf[3] = 0x10 | ccounter;       // Set payload flag, Continuity counter | ||||
| 							tspat_buf[8] = (ts_id >> 8);          // Transport stream ID (bits 8-15) | ||||
| 							tspat_buf[9] = (ts_id & 0xff);        // Transport stream ID (bits 0-7) | ||||
| 							tspat_buf[10] = 0xc0 | ((pat.getVersionNumber() << 1) & 0x3e) | | ||||
| 								pat.getCurrentNextIndicator();// Version number, Current next indicator | ||||
| 							tspat_buf[13] = (pmtSid >> 8);        // Program number (bits 8-15) | ||||
| 							tspat_buf[14] = (pmtSid & 0xff);      // Program number (bits 0-7) | ||||
| 							tspat_buf[15] = 0xe0 | (pmtPid >> 8); // Network ID (bits 8-12) | ||||
| 							tspat_buf[16] = (pmtPid & 0xff);      // Network ID (bits 0-7) | ||||
| 							crc = 0xffffffff; | ||||
| 							len = 12;                             // PAT_TABLE_LEN | ||||
| 							tmp = &tspat_buf[4 + 1];              // TS_HDR_LEN + 1 | ||||
| 							while (len--) { | ||||
| 								crc ^= *tmp++ << 24; | ||||
| 								for (i = 0; i < 8; i++) | ||||
| 									crc = (crc << 1) ^ ((crc & 0x80000000) ? 0x04c11db7 : 0); // CRC32POLY | ||||
| 							} | ||||
| 							tspat_buf[17] = crc >> 24 & 0xff;     // Checksum | ||||
| 							tspat_buf[18] = crc >> 16 & 0xff;     // Checksum | ||||
| 							tspat_buf[19] = crc >>  8 & 0xff;     // Checksum | ||||
| 							tspat_buf[20] = crc & 0xff;           // Checksum | ||||
| 							int written = siBuffer.PutTS(tspat_buf, TS_SIZE); | ||||
| 							if (written != TS_SIZE) | ||||
| 								siBuffer.ReportOverflow(TS_SIZE - written); | ||||
| 							if (pmtPid != prevPmtPid) { | ||||
| 								m_Streamer->SetPids(pmtPid); | ||||
| 								Add(pmtPid, 0x02); | ||||
| @@ -292,7 +303,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i | ||||
| 		if (pmtVersion != -1) { | ||||
| 			if (pmtVersion != pmt.getVersionNumber()) { | ||||
| 				Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids\n"); | ||||
| 				Del(pmtPid, 0x02); | ||||
| 				cFilter::Del(pmtPid, 0x02); | ||||
| 				pmtPid = 0; // this triggers PAT scan | ||||
| 			} | ||||
| 			return; | ||||
| @@ -329,9 +340,7 @@ cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Paramet | ||||
| 		m_Device(NULL), | ||||
| 		m_Receiver(NULL), | ||||
| 		m_PatFilter(NULL), | ||||
| #if APIVERSNUM < 10703 | ||||
| 		m_PESRemux(NULL), | ||||
| #endif | ||||
| 		m_ESRemux(NULL), | ||||
| 		m_PSRemux(NULL), | ||||
| 		m_ExtRemux(NULL) | ||||
| @@ -347,9 +356,7 @@ cStreamdevLiveStreamer::~cStreamdevLiveStreamer() | ||||
| 		DELETENULL(m_PatFilter); | ||||
| 	} | ||||
| 	DELETENULL(m_Receiver); | ||||
| #if APIVERSNUM < 10703 | ||||
| 	delete m_PESRemux; | ||||
| #endif | ||||
| 	delete m_ESRemux; | ||||
| 	delete m_PSRemux; | ||||
| 	delete m_ExtRemux; | ||||
| @@ -463,12 +470,10 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str | ||||
| 			return SetPids(pid); | ||||
| 		} | ||||
|  | ||||
| #if APIVERSNUM < 10703 | ||||
| 	case stPES:  | ||||
| 		m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),  | ||||
| 								m_Channel->Spids(), false); | ||||
| 		m_PESRemux = new cTS2PESRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),  | ||||
| 								m_Channel->Spids()); | ||||
| 		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); | ||||
| #endif | ||||
|  | ||||
| 	case stPS:   | ||||
| 		m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), | ||||
| @@ -505,13 +510,22 @@ int cStreamdevLiveStreamer::Put(const uchar *Data, int Count) | ||||
| { | ||||
| 	switch (m_StreamType) { | ||||
| 	case stTS: | ||||
| 		// insert si data | ||||
| 		if (m_PatFilter) { | ||||
| 			int got; | ||||
| 			uchar *si = m_PatFilter->Get(got); | ||||
| 			if (si) { | ||||
| 				int count = cStreamdevStreamer::Put(si, got); | ||||
| 				if (count) | ||||
| 					m_PatFilter->Del(count); | ||||
| 			} | ||||
| 		} | ||||
| 		// fall through | ||||
| 	case stTSPIDS: | ||||
| 		return cStreamdevStreamer::Put(Data, Count); | ||||
|  | ||||
| #if APIVERSNUM < 10703 | ||||
| 	case stPES: | ||||
| 		return m_PESRemux->Put(Data, Count); | ||||
| #endif | ||||
|  | ||||
| 	case stES: | ||||
| 		return m_ESRemux->Put(Data, Count); | ||||
| @@ -534,10 +548,8 @@ uchar *cStreamdevLiveStreamer::Get(int &Count) | ||||
| 	case stTSPIDS: | ||||
| 		return cStreamdevStreamer::Get(Count); | ||||
|  | ||||
| #if APIVERSNUM < 10703 | ||||
| 	case stPES: | ||||
| 		return m_PESRemux->Get(Count); | ||||
| #endif | ||||
| 	 | ||||
| 	case stES: | ||||
| 		return m_ESRemux->Get(Count); | ||||
| @@ -561,11 +573,9 @@ void cStreamdevLiveStreamer::Del(int Count) | ||||
| 		cStreamdevStreamer::Del(Count); | ||||
| 		break; | ||||
|  | ||||
| #if APIVERSNUM < 10703 | ||||
| 	case stPES: | ||||
| 		m_PESRemux->Del(Count); | ||||
| 		break; | ||||
| #endif | ||||
| 	 | ||||
| 	case stES: | ||||
| 		m_ESRemux->Del(Count); | ||||
|   | ||||
| @@ -7,12 +7,12 @@ | ||||
| #include "server/streamer.h" | ||||
| #include "common.h" | ||||
|  | ||||
| class cTS2PSRemux; | ||||
| class cTS2ESRemux; | ||||
| class cExternRemux; | ||||
| #if APIVERSNUM < 10703 | ||||
| class cRemux; | ||||
| #endif | ||||
| namespace Streamdev { | ||||
| 	class cTS2PSRemux; | ||||
| 	class cTS2ESRemux; | ||||
| 	class cExternRemux; | ||||
| 	class cTS2PESRemux; | ||||
| } | ||||
| class cStreamdevPatFilter; | ||||
| class cStreamdevLiveReceiver; | ||||
|  | ||||
| @@ -29,12 +29,10 @@ private: | ||||
| 	cDevice                *m_Device; | ||||
| 	cStreamdevLiveReceiver *m_Receiver; | ||||
| 	cStreamdevPatFilter    *m_PatFilter; | ||||
| #if APIVERSNUM < 10703 | ||||
| 	cRemux                 *m_PESRemux; | ||||
| #endif | ||||
| 	cTS2ESRemux            *m_ESRemux; | ||||
| 	cTS2PSRemux            *m_PSRemux; | ||||
| 	cExternRemux           *m_ExtRemux; | ||||
| 	Streamdev::cTS2PESRemux *m_PESRemux; | ||||
| 	Streamdev::cTS2ESRemux  *m_ESRemux; | ||||
| 	Streamdev::cTS2PSRemux  *m_PSRemux; | ||||
| 	Streamdev::cExternRemux *m_ExtRemux; | ||||
|  | ||||
| 	void StartReceiver(void); | ||||
| 	bool HasPid(int Pid); | ||||
|   | ||||
| @@ -201,10 +201,8 @@ std::string cHtmlChannelList::StreamTypeMenu() | ||||
| 			(std::string) "[<a href=\"/TS/" + self + "\">TS</a>] "); | ||||
| 	typeMenu += (streamType == stPS ? (std::string) "[PS] " : | ||||
| 			(std::string) "[<a href=\"/PS/" + self + "\">PS</a>] "); | ||||
| #if APIVERSNUM < 10703 | ||||
| 	typeMenu += (streamType == stPES ? (std::string) "[PES] " : | ||||
| 			(std::string) "[<a href=\"/PES/" + self + "\">PES</a>] "); | ||||
| #endif | ||||
| 	typeMenu += (streamType == stES ? (std::string) "[ES] " : | ||||
| 			(std::string) "[<a href=\"/ES/" + self + "\">ES</a>] "); | ||||
| 	typeMenu += (streamType == stExtern ? (std::string) "[Extern] " : | ||||
| @@ -343,10 +341,8 @@ std::string cHtmlChannelList::ItemText() | ||||
| 	switch (streamType) { | ||||
| 		case stTS: suffix = (std::string) ".ts"; break; | ||||
| 		case stPS: suffix = (std::string) ".vob"; break; | ||||
| #if APIVERSNUM < 10703 | ||||
| 		// for Network Media Tank | ||||
| 		case stPES: suffix = (std::string) ".vdr"; break;  | ||||
| #endif | ||||
| 		default: suffix = ""; | ||||
| 	} | ||||
| 	line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">"; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  *  $Id: streamer.c,v 1.18 2009/02/13 10:39:22 schmirl Exp $ | ||||
|  *  $Id: streamer.c,v 1.19 2009/06/19 06:32:45 schmirl Exp $ | ||||
|  */ | ||||
|   | ||||
| #include <vdr/ringbuffer.h> | ||||
| @@ -14,6 +14,13 @@ | ||||
| #include "tools/select.h" | ||||
| #include "common.h" | ||||
|  | ||||
| // --- cStreamdevBuffer ------------------------------------------------------- | ||||
|  | ||||
| cStreamdevBuffer::cStreamdevBuffer(int Size, int Margin, bool Statistics, const char *Description): | ||||
| 		cRingBufferLinear(Size, Margin, Statistics, Description) | ||||
| { | ||||
| } | ||||
|  | ||||
| // --- cStreamdevWriter ------------------------------------------------------- | ||||
|  | ||||
| cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket,  | ||||
| @@ -95,14 +102,13 @@ void cStreamdevWriter::Action(void) | ||||
|  | ||||
| cStreamdevStreamer::cStreamdevStreamer(const char *Name): | ||||
| 		cThread(Name), | ||||
| 		m_Running(false), | ||||
| 		m_Writer(NULL), | ||||
| 		m_RingBuffer(new cRingBufferLinear(STREAMERBUFSIZE, TS_SIZE * 2, | ||||
| 		m_RingBuffer(new cStreamdevBuffer(STREAMERBUFSIZE, TS_SIZE * 2, | ||||
| 		             true, "streamdev-streamer")), | ||||
| 		m_SendBuffer(new cRingBufferLinear(WRITERBUFSIZE, TS_SIZE * 2)) | ||||
| 		m_SendBuffer(new cStreamdevBuffer(WRITERBUFSIZE, TS_SIZE * 2)) | ||||
| { | ||||
| 	m_RingBuffer->SetTimeouts(0, 100); | ||||
| 	m_SendBuffer->SetTimeouts(0, 100); | ||||
| 	m_SendBuffer->SetTimeouts(100, 100); | ||||
| } | ||||
|  | ||||
| cStreamdevStreamer::~cStreamdevStreamer()  | ||||
| @@ -116,7 +122,6 @@ void cStreamdevStreamer::Start(cTBSocket *Socket) | ||||
| { | ||||
| 	Dprintf("start streamer\n"); | ||||
| 	m_Writer = new cStreamdevWriter(Socket, this); | ||||
| 	m_Running = true; | ||||
| 	Attach(); | ||||
| } | ||||
|  | ||||
| @@ -135,9 +140,8 @@ void cStreamdevStreamer::Stop(void) | ||||
| 		Dprintf("stopping streamer\n"); | ||||
| 		Cancel(3); | ||||
| 	} | ||||
| 	if (m_Running) { | ||||
| 	if (m_Writer) { | ||||
| 		Detach(); | ||||
| 		m_Running = false; | ||||
| 		DELETENULL(m_Writer); | ||||
| 	} | ||||
| } | ||||
| @@ -152,8 +156,6 @@ void cStreamdevStreamer::Action(void) | ||||
| 			int count = Put(block, got); | ||||
| 			if (count) | ||||
| 				m_RingBuffer->Del(count); | ||||
| 			else | ||||
| 				cCondWait::SleepMs(100); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  *  $Id: streamer.h,v 1.10 2009/02/13 10:39:22 schmirl Exp $ | ||||
|  *  $Id: streamer.h,v 1.11 2009/06/19 06:32:45 schmirl Exp $ | ||||
|  */ | ||||
|   | ||||
| #ifndef VDR_STREAMDEV_STREAMER_H | ||||
| @@ -16,8 +16,34 @@ class cStreamdevStreamer; | ||||
| #define TS_SIZE 188 | ||||
| #endif | ||||
|  | ||||
| #define STREAMERBUFSIZE MEGABYTE(4) | ||||
| #define WRITERBUFSIZE KILOBYTE(256) | ||||
| #define STREAMERBUFSIZE (20000 * TS_SIZE) | ||||
| #define WRITERBUFSIZE (5000 * TS_SIZE) | ||||
|  | ||||
| // --- cStreamdevBuffer ------------------------------------------------------- | ||||
|  | ||||
| class cStreamdevBuffer: public cRingBufferLinear { | ||||
| public: | ||||
| 	// make public | ||||
| 	void WaitForPut(void) { cRingBuffer::WaitForPut(); } | ||||
| 	// Always write complete TS packets | ||||
| 	// (assumes Count is a multiple of TS_SIZE) | ||||
| 	int PutTS(const uchar *Data, int Count); | ||||
| 	cStreamdevBuffer(int Size, int Margin = 0, bool Statistics = false, const char *Description = NULL); | ||||
| }; | ||||
|  | ||||
| inline int cStreamdevBuffer::PutTS(const uchar *Data, int Count) | ||||
| { | ||||
| 	int free = Free(); | ||||
| 	if (free < Count) | ||||
| 		Count = free; | ||||
|  | ||||
| 	Count -= Count % TS_SIZE; | ||||
| 	if (Count) | ||||
| 		Count = Put(Data, Count); | ||||
| 	else | ||||
| 		WaitForPut(); | ||||
| 	return Count; | ||||
| } | ||||
|  | ||||
| // --- cStreamdevWriter ------------------------------------------------------- | ||||
|  | ||||
| @@ -38,15 +64,14 @@ public: | ||||
|  | ||||
| class cStreamdevStreamer: public cThread { | ||||
| private: | ||||
| 	bool               m_Running; | ||||
| 	cStreamdevWriter  *m_Writer; | ||||
| 	cRingBufferLinear *m_RingBuffer; | ||||
| 	cRingBufferLinear *m_SendBuffer; | ||||
| 	cStreamdevBuffer  *m_RingBuffer; | ||||
| 	cStreamdevBuffer  *m_SendBuffer; | ||||
|  | ||||
| protected: | ||||
| 	virtual void Action(void); | ||||
|  | ||||
| 	bool IsRunning(void) const { return m_Running; } | ||||
| 	bool IsRunning(void) const { return m_Writer; } | ||||
|  | ||||
| public: | ||||
| 	cStreamdevStreamer(const char *Name); | ||||
| @@ -57,10 +82,10 @@ public: | ||||
| 	bool Abort(void); | ||||
|  | ||||
| 	void Activate(bool On); | ||||
| 	int Receive(uchar *Data, int Length) { return m_RingBuffer->Put(Data, Length); } | ||||
| 	int Receive(uchar *Data, int Length) { return m_RingBuffer->PutTS(Data, Length); } | ||||
| 	void ReportOverflow(int Bytes) { m_RingBuffer->ReportOverflow(Bytes); } | ||||
| 	 | ||||
| 	virtual int Put(const uchar *Data, int Count) { return m_SendBuffer->Put(Data, Count); } | ||||
| 	virtual int Put(const uchar *Data, int Count) { return m_SendBuffer->PutTS(Data, Count); } | ||||
| 	virtual uchar *Get(int &Count) { return m_SendBuffer->Get(Count); } | ||||
| 	virtual void Del(int Count) { m_SendBuffer->Del(Count); } | ||||
|  | ||||
|   | ||||
| @@ -3,12 +3,11 @@ | ||||
|  * | ||||
|  * See the README file for copyright information and how to reach the author. | ||||
|  * | ||||
|  * $Id: streamdev-server.c,v 1.11 2008/10/14 11:05:47 schmirl Exp $ | ||||
|  * $Id: streamdev-server.c,v 1.12 2009/06/19 06:32:38 schmirl Exp $ | ||||
|  */ | ||||
|  | ||||
| #include <getopt.h> | ||||
| #include <vdr/tools.h> | ||||
| #include "remux/extern.h" | ||||
| #include "streamdev-server.h" | ||||
| #include "server/setup.h" | ||||
| #include "server/server.h" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user