mirror of
				https://github.com/rofafor/vdr-plugin-iptv.git
				synced 2023-10-10 11:37:03 +00:00 
			
		
		
		
	New and improved section filter code from Kernel. Objectified neatly in
separate class.
This commit is contained in:
		
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| # | ||||
| # Makefile for a Video Disk Recorder plugin | ||||
| # | ||||
| # $Id: Makefile,v 1.7 2007/09/19 15:14:32 ajhseppa Exp $ | ||||
| # $Id: Makefile,v 1.8 2007/09/24 13:03:38 ajhseppa Exp $ | ||||
|  | ||||
| # Debugging on/off  | ||||
| #IPTV_DEBUG = 1 | ||||
| @@ -57,7 +57,7 @@ endif | ||||
|  | ||||
| ### The object files (add further files here): | ||||
|  | ||||
| OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o protocolhttp.o protocolfile.o pidfilter.o | ||||
| OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o protocolhttp.o protocolfile.o sectionfilter.o | ||||
|  | ||||
| ### The main target: | ||||
|  | ||||
|   | ||||
							
								
								
									
										100
									
								
								device.c
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								device.c
									
									
									
									
									
								
							| @@ -3,15 +3,13 @@ | ||||
|  * | ||||
|  * See the README file for copyright information and how to reach the author. | ||||
|  * | ||||
|  * $Id: device.c,v 1.35 2007/09/22 17:37:57 rahrenbe Exp $ | ||||
|  * $Id: device.c,v 1.36 2007/09/24 13:03:38 ajhseppa Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "common.h" | ||||
| #include "config.h" | ||||
| #include "device.h" | ||||
|  | ||||
| #define IPTV_FILTER_FILENAME "/tmp/vdr-iptv%d.filter%d" | ||||
|  | ||||
| #define IPTV_MAX_DEVICES 8 | ||||
|  | ||||
| cIptvDevice * IptvDevices[IPTV_MAX_DEVICES]; | ||||
| @@ -34,21 +32,9 @@ cIptvDevice::cIptvDevice(unsigned int Index) | ||||
|   pHttpProtocol = new cIptvProtocolHttp(); | ||||
|   pFileProtocol = new cIptvProtocolFile(); | ||||
|   pIptvStreamer = new cIptvStreamer(tsBuffer, &mutex); | ||||
|   // Initialize filters   | ||||
|   memset(&filter, '\0', sizeof(filter)); | ||||
|   init_trans(&filter); | ||||
|   for (int i = 0; i < eMaxFilterCount; ++i) { | ||||
|       struct stat sb; | ||||
|       snprintf(filters[i].pipeName, sizeof(filters[i].pipeName), | ||||
|                IPTV_FILTER_FILENAME, deviceIndex, i); | ||||
|       stat(filters[i].pipeName, &sb); | ||||
|       if (S_ISFIFO(sb.st_mode)) | ||||
|          unlink(filters[i].pipeName); | ||||
|       memset(filters[i].pipeName, '\0', sizeof(filters[i].pipeName)); | ||||
|       filters[i].fifoDesc = -1; | ||||
|       filters[i].readDesc = -1; | ||||
|       filters[i].active = false; | ||||
|       } | ||||
|   // Initialize filter pointers | ||||
|   memset(&secfilters, '\0', sizeof(secfilters)); | ||||
|  | ||||
|   StartSectionHandler(); | ||||
| } | ||||
|  | ||||
| @@ -58,7 +44,7 @@ cIptvDevice::~cIptvDevice() | ||||
|   delete pIptvStreamer; | ||||
|   delete pUdpProtocol; | ||||
|   delete tsBuffer; | ||||
|   // Iterate over all filters and clear their settings  | ||||
|   // Destroy all filters | ||||
|   for (int i = 0; i < eMaxFilterCount; ++i) | ||||
|       DeleteFilter(i); | ||||
| } | ||||
| @@ -170,15 +156,9 @@ bool cIptvDevice::SetPid(cPidHandle *Handle, int Type, bool On) | ||||
| bool cIptvDevice::DeleteFilter(unsigned int Index) | ||||
| { | ||||
|   debug("cIptvDevice::DeleteFilter(%d) Index=%d\n", deviceIndex, Index); | ||||
|   if ((Index < eMaxFilterCount) && filters[Index].active) { | ||||
|      close(filters[Index].fifoDesc); | ||||
|      close(filters[Index].readDesc); | ||||
|      unlink(filters[Index].pipeName); | ||||
|      memset(filters[Index].pipeName, '\0', sizeof(filters[Index].pipeName)); | ||||
|      filters[Index].fifoDesc = -1; | ||||
|      filters[Index].readDesc = -1; | ||||
|      filters[Index].active = false; | ||||
|      clear_trans_filt(&filter, Index); | ||||
|   if ((Index < eMaxFilterCount) && secfilters[Index]) { | ||||
|      delete secfilters[Index]; | ||||
|      secfilters[Index] = NULL; | ||||
|      return true; | ||||
|      } | ||||
|   return false; | ||||
| @@ -188,33 +168,12 @@ int cIptvDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) | ||||
| { | ||||
|   // Search the next free filter slot | ||||
|   for (unsigned int i = 0; i < eMaxFilterCount; ++i) { | ||||
|       if (!filters[i].active) { | ||||
|       if (!secfilters[i]) { | ||||
|          debug("cIptvDevice::OpenFilter(%d): Pid=%d Tid=%02X Mask=%02X Index=%d\n", deviceIndex, Pid, Tid, Mask, i); | ||||
|          uint8_t mask[eMaxFilterMaskLen] = { 0 }; | ||||
|          uint8_t filt[eMaxFilterMaskLen] = { 0 }; | ||||
|          mask[0] = Mask; | ||||
|          filt[0] = Tid; | ||||
|          int err = set_trans_filt(&filter, i, Pid, &mask[0], &filt[0], 0); | ||||
|          if (err < 0) | ||||
|             error("Cannot set filter %d\n", i); | ||||
|          memset(filters[i].pipeName, '\0', sizeof(filters[i].pipeName)); | ||||
|          snprintf(filters[i].pipeName, sizeof(filters[i].pipeName), | ||||
|                   IPTV_FILTER_FILENAME, deviceIndex, i); | ||||
|          struct stat sb; | ||||
|          stat(filters[i].pipeName, &sb); | ||||
|          if (S_ISFIFO(sb.st_mode)) | ||||
|             unlink(filters[i].pipeName); | ||||
|          err = mknod(filters[i].pipeName, 0644 | S_IFIFO, 0); | ||||
|          if (err < 0) { | ||||
|             char tmp[64]; | ||||
|             error("ERROR: mknod(): %s", strerror_r(errno, tmp, sizeof(tmp))); | ||||
|             break; | ||||
|             } | ||||
|          // Create descriptors | ||||
|          filters[i].fifoDesc = open(filters[i].pipeName, O_RDWR | O_NONBLOCK); | ||||
|          filters[i].readDesc = open(filters[i].pipeName, O_RDONLY | O_NONBLOCK); | ||||
|          filters[i].active = true; | ||||
|          return filters[i].readDesc; | ||||
| 	  | ||||
|          secfilters[i] = new cIptvSectionFilter(i, deviceIndex, Pid, Tid, | ||||
|                                                 Mask); | ||||
|          return secfilters[i]->GetReadDesc(); | ||||
|          } | ||||
|       } | ||||
|   // No free filter slot found | ||||
| @@ -225,7 +184,7 @@ bool cIptvDevice::CloseFilter(int Handle) | ||||
| { | ||||
|   debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle); | ||||
|   for (unsigned int i = 0; i < eMaxFilterCount; ++i) { | ||||
|       if (Handle == filters[i].readDesc) | ||||
|       if (Handle == secfilters[i]->GetReadDesc()) | ||||
|          return DeleteFilter(i); | ||||
|       } | ||||
|   return false; | ||||
| @@ -300,35 +259,10 @@ bool cIptvDevice::GetTSPacket(uchar *&Data) | ||||
|            } | ||||
|         isPacketDelivered = true; | ||||
|         Data = p; | ||||
|         memcpy(filter.packet, p, sizeof(filter.packet)); | ||||
|         trans_filt(p, TS_SIZE, &filter); | ||||
|         // Run the data through all filters | ||||
|         for (unsigned int i = 0; i < eMaxFilterCount; ++i) { | ||||
|             if (filters[i].active) { | ||||
|                section *filtered = get_filt_sec(&filter, i); | ||||
|                if (filtered->found) { | ||||
|                   // Select on the fifo emptyness. Using null timeout to return immediately | ||||
|                   struct timeval tv; | ||||
|                   tv.tv_sec = 0; | ||||
|                   tv.tv_usec = 0; | ||||
|                   fd_set rfds; | ||||
|                   FD_ZERO(&rfds); | ||||
|                   FD_SET(filters[i].fifoDesc, &rfds); | ||||
|                   int retval = select(filters[i].fifoDesc + 1, &rfds, NULL, NULL, &tv); | ||||
|                   // Check if error | ||||
|                   if (retval < 0) { | ||||
|                      char tmp[64]; | ||||
|                      error("ERROR: select(): %s", strerror_r(errno, tmp, sizeof(tmp))); | ||||
|                      DeleteFilter(i); | ||||
|                      } | ||||
|                   // There is no data in the fifo, more can be written | ||||
|                   else if (!retval) { | ||||
|                      int err = write(filters[i].fifoDesc, filtered->payload, filtered->length + 3); | ||||
|                      if (err < 0) { | ||||
|                         char tmp[64]; | ||||
|                         error("ERROR: write(): %s", strerror_r(errno, tmp, sizeof(tmp))); | ||||
|                         } | ||||
|                     } | ||||
|                   } | ||||
|             if (secfilters[i]) { | ||||
|                secfilters[i]->ProcessData(p); | ||||
|                } | ||||
|             } | ||||
|         return true; | ||||
|   | ||||
							
								
								
									
										15
									
								
								device.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								device.h
									
									
									
									
									
								
							| @@ -3,7 +3,7 @@ | ||||
|  * | ||||
|  * See the README file for copyright information and how to reach the author. | ||||
|  * | ||||
|  * $Id: device.h,v 1.15 2007/09/22 08:17:35 ajhseppa Exp $ | ||||
|  * $Id: device.h,v 1.16 2007/09/24 13:03:38 ajhseppa Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __IPTV_DEVICE_H | ||||
| @@ -16,15 +16,8 @@ | ||||
| #include "protocolfile.h" | ||||
| #include "streamer.h" | ||||
|  | ||||
| #include "pidfilter.h" | ||||
| #include "sectionfilter.h" | ||||
|  | ||||
| struct filterInfo { | ||||
|   bool active; | ||||
|   int fifoDesc; | ||||
|   int readDesc; | ||||
|   char pipeName[128]; | ||||
|   int lastProvided;  | ||||
| }; | ||||
|  | ||||
| class cIptvDevice : public cDevice { | ||||
|   // static ones | ||||
| @@ -38,7 +31,6 @@ public: | ||||
| private: | ||||
|   enum { | ||||
|     eMaxFilterCount   = 32, | ||||
|     eMaxFilterMaskLen = 16 | ||||
|   }; | ||||
|   unsigned int deviceIndex; | ||||
|   bool isPacketDelivered; | ||||
| @@ -50,8 +42,7 @@ private: | ||||
|   cIptvProtocolFile *pFileProtocol; | ||||
|   cIptvStreamer *pIptvStreamer; | ||||
|   cMutex mutex; | ||||
|   trans filter; | ||||
|   filterInfo filters[eMaxFilterCount]; | ||||
|   cIptvSectionFilter* secfilters[eMaxFilterCount]; | ||||
|  | ||||
|   // constructor & destructor | ||||
| public: | ||||
|   | ||||
							
								
								
									
										354
									
								
								sectionfilter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								sectionfilter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,354 @@ | ||||
| /* | ||||
|  * sectionfilter.c: IPTV plugin for the Video Disk Recorder | ||||
|  * | ||||
|  * See the README file for copyright information and how to reach the author. | ||||
|  * | ||||
|  * $Id: sectionfilter.c,v 1.1 2007/09/24 13:03:38 ajhseppa Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "sectionfilter.h" | ||||
|  | ||||
| #define IPTV_FILTER_FILENAME "/tmp/vdr-iptv%d.filter%d" | ||||
|  | ||||
| cIptvSectionFilter::cIptvSectionFilter(int Index, int devInd, | ||||
| 				       u_short Pid, u_char Tid, u_char Mask) | ||||
|   :  pusi_seen(0), | ||||
|      feedcc(0), | ||||
|      doneq(0), | ||||
|      secbuf(NULL), | ||||
|      secbufp(0), | ||||
|      seclen(0), | ||||
|      tsfeedp(0), | ||||
|      crc_val(0), | ||||
|      pid(Pid), | ||||
|      id(Index) | ||||
| { | ||||
|   debug("cIptvSectionFilter::cIptvSectionFilter(%d)\n", Index); | ||||
|    | ||||
|   memset(secbuf_base, '\0', sizeof(secbuf_base)); | ||||
|   memset(filter_value, '\0', sizeof(filter_value)); | ||||
|   memset(filter_mask, '\0', sizeof(filter_mask)); | ||||
|   memset(filter_mode, '\0', sizeof(filter_mode)); | ||||
|   memset(maskandmode, '\0', sizeof(maskandmode)); | ||||
|   memset(maskandnotmode, '\0', sizeof(maskandnotmode)); | ||||
|   memset(pipeName, '\0', sizeof(pipeName)); | ||||
|  | ||||
|   SetPipeName(devInd); | ||||
|  | ||||
|   filter_value[0] = !Tid; | ||||
|   filter_mask[0] = Mask; | ||||
|  | ||||
|   uint8_t mask, mode, local_doneq = 0; | ||||
|   for (int i = 0; i < DVB_DEMUX_MASK_MAX; i++) { | ||||
|     mode = filter_mode[i]; | ||||
|     mask = filter_mask[i]; | ||||
|     maskandmode[i] = mask & mode; | ||||
|     local_doneq |= maskandnotmode[i] = mask & ~mode; | ||||
|   } | ||||
|   doneq = local_doneq ? 1 : 0; | ||||
|  | ||||
|   struct stat sb; | ||||
|   stat(pipeName, &sb); | ||||
|   if (S_ISFIFO(sb.st_mode)) | ||||
|     unlink(pipeName); | ||||
|   int err = mknod(pipeName, 0644 | S_IFIFO, 0); | ||||
|   if (err < 0) { | ||||
|     char tmp[64]; | ||||
|     error("ERROR: mknod(): %s", strerror_r(errno, tmp, sizeof(tmp))); | ||||
|     return; | ||||
|     } | ||||
|  | ||||
|   // Create descriptors | ||||
|   fifoDescriptor = open(pipeName, O_RDWR | O_NONBLOCK); | ||||
|   readDescriptor = open(pipeName, O_RDONLY | O_NONBLOCK); | ||||
| } | ||||
|  | ||||
| cIptvSectionFilter::~cIptvSectionFilter() | ||||
| { | ||||
|   debug("cIptvSectionFilter::~cIptvSectionfilter()\n"); | ||||
|   close(fifoDescriptor); | ||||
|   close(readDescriptor); | ||||
|   unlink(pipeName); | ||||
|   memset(pipeName, '\0', sizeof(pipeName)); | ||||
|   fifoDescriptor = -1; | ||||
|   readDescriptor = -1; | ||||
| } | ||||
|  | ||||
| void cIptvSectionFilter::SetPipeName(int deviceIndex) | ||||
| { | ||||
|   snprintf(pipeName, sizeof(pipeName), IPTV_FILTER_FILENAME, deviceIndex, id); | ||||
| } | ||||
|  | ||||
| int cIptvSectionFilter::GetReadDesc() | ||||
| { | ||||
|   return readDescriptor; | ||||
| } | ||||
|  | ||||
| inline uint16_t cIptvSectionFilter::section_length(const uint8_t *buf) | ||||
| { | ||||
|   return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; | ||||
| } | ||||
|  | ||||
| inline uint16_t cIptvSectionFilter::ts_pid(const uint8_t *buf) | ||||
| { | ||||
|   return ((buf[1] & 0x1f) << 8) + buf[2]; | ||||
| } | ||||
|  | ||||
| inline uint8_t cIptvSectionFilter::payload(const uint8_t *tsp) | ||||
| { | ||||
|   if (!(tsp[3] & 0x10))	// no payload? | ||||
|     return 0; | ||||
|  | ||||
|   if (tsp[3] & 0x20) {	// adaptation field? | ||||
|     if (tsp[4] > 183)	// corrupted data? | ||||
|       return 0; | ||||
|     else | ||||
|       return 184 - 1 - tsp[4]; | ||||
|   } | ||||
|  | ||||
|   return 184; | ||||
| } | ||||
|  | ||||
| int cIptvSectionFilter::dvb_dmxdev_section_callback(const uint8_t *buffer1, size_t buffer1_len, | ||||
| 				       const uint8_t *buffer2, size_t buffer2_len, | ||||
| 				       enum dmx_success success) | ||||
| { | ||||
|   struct timeval tv; | ||||
|   tv.tv_sec = 0; | ||||
|   tv.tv_usec = 0; | ||||
|   fd_set rfds; | ||||
|   FD_ZERO(&rfds); | ||||
|   FD_SET(fifoDescriptor, &rfds); | ||||
|   int retval = select(fifoDescriptor + 1, &rfds, NULL, NULL, &tv); | ||||
|  | ||||
|   // Check if error | ||||
|   if (retval < 0) { | ||||
|     char tmp[64]; | ||||
|     error("ERROR: select(): %s", strerror_r(errno, tmp, sizeof(tmp))); | ||||
|   } | ||||
|   // There is no data in the fifo, more can be written | ||||
|   else if (!retval) { | ||||
| #ifdef DEBUG_PRINTF | ||||
|     printf("id = %d, pid %d would now write %d data to buffer\n", id, pid, buffer1_len); | ||||
|     for (unsigned int i = 0; i < buffer1_len; ++i) { | ||||
|       printf("0x%X ", buffer1[i]); | ||||
|     } | ||||
|     printf("\n"); | ||||
| #endif | ||||
|  | ||||
|     retval = write(fifoDescriptor, buffer1, buffer1_len); | ||||
|  | ||||
|     if (retval < 0) { | ||||
|       char tmp[64]; | ||||
|       error("ERROR: write(): %s", strerror_r(errno, tmp, sizeof(tmp))); | ||||
|     } | ||||
|   } | ||||
| #ifdef DEBUG_PRINTF | ||||
|   else if (retval) { | ||||
|     printf("id %d pid %d data is already present\n", id, pid); | ||||
|   } | ||||
| #endif | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| void cIptvSectionFilter::dvb_dmx_swfilter_section_new() | ||||
| { | ||||
| #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||||
|   if (secbufp < tsfeedp) { | ||||
|     int i, n = tsfeedp - secbufp; | ||||
|  | ||||
|     /* | ||||
|      * Section padding is done with 0xff bytes entirely. | ||||
|      * Due to speed reasons, we won't check all of them | ||||
|      * but just first and last. | ||||
|      */ | ||||
|     if (secbuf[0] != 0xff || secbuf[n - 1] != 0xff) { | ||||
|       printf("dvb_demux.c section ts padding loss: %d/%d\n", | ||||
| 	     n, tsfeedp); | ||||
|       printf("dvb_demux.c pad data:"); | ||||
|       for (i = 0; i < n; i++) | ||||
| 	printf(" %02x", secbuf[i]); | ||||
|       printf("\n"); | ||||
|     } | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   tsfeedp = secbufp = seclen = 0; | ||||
|   secbuf = secbuf_base; | ||||
| } | ||||
|  | ||||
|  | ||||
| int cIptvSectionFilter::dvb_dmx_swfilter_sectionfilter() | ||||
| { | ||||
|   uint8_t neq = 0; | ||||
|   int i; | ||||
|  | ||||
|   for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { | ||||
|     uint8_t local_xor = filter_value[i] ^ secbuf[i]; | ||||
|  | ||||
|     if (maskandmode[i] & local_xor) { | ||||
| #ifdef DEBUG_PRINTF | ||||
|       printf("maskandmode discard\n"); | ||||
| #endif | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     neq |= maskandnotmode[i] & local_xor; | ||||
|   } | ||||
|  | ||||
|   if (doneq && !neq) { | ||||
| #ifdef DEBUG_PRINTF | ||||
|     printf("doneq discard, doneq = 0x%X, neq = 0x%X\n", doneq, !neq); | ||||
| #endif | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return dvb_dmxdev_section_callback(secbuf, seclen, NULL, 0, DMX_OK); | ||||
| } | ||||
|  | ||||
| inline int cIptvSectionFilter::dvb_dmx_swfilter_section_feed() | ||||
| { | ||||
|   if (dvb_dmx_swfilter_sectionfilter() < 0) | ||||
|     return -1; | ||||
|    | ||||
|   seclen = 0; | ||||
|    | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int cIptvSectionFilter::dvb_dmx_swfilter_section_copy_dump(const uint8_t *buf, uint8_t len) | ||||
| { | ||||
|   uint16_t limit, seclen_local, n; | ||||
|  | ||||
|   if (tsfeedp >= DMX_MAX_SECFEED_SIZE) { | ||||
|     return 0; | ||||
|   } | ||||
|   if (tsfeedp + len > DMX_MAX_SECFEED_SIZE) { | ||||
| #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||||
|     printf("dvb_demux.c section buffer full loss: %d/%d\n", | ||||
| 	   tsfeedp + len - DMX_MAX_SECFEED_SIZE, | ||||
| 	   DMX_MAX_SECFEED_SIZE); | ||||
| #endif | ||||
|     len = DMX_MAX_SECFEED_SIZE - tsfeedp; | ||||
|   } | ||||
|  | ||||
|   if (len <= 0) | ||||
|     return 0; | ||||
|  | ||||
|   memcpy(secbuf_base + tsfeedp, buf, len); | ||||
|   tsfeedp += len; | ||||
|  | ||||
|   /* | ||||
|    * Dump all the sections we can find in the data (Emard) | ||||
|    */ | ||||
|   limit = tsfeedp; | ||||
|   if (limit > DMX_MAX_SECFEED_SIZE) { | ||||
|     return -1;	/* internal error should never happen */ | ||||
|   } | ||||
|  | ||||
|   /* to be sure always set secbuf */ | ||||
|   secbuf = secbuf_base + secbufp; | ||||
|  | ||||
|   for (n = 0; secbufp + 2 < limit; n++) { | ||||
|     seclen_local = section_length(secbuf); | ||||
|     if (seclen_local <= 0 || seclen_local > DMX_MAX_SECTION_SIZE | ||||
| 	|| seclen_local + secbufp > limit) { | ||||
|       return 0; | ||||
|     } | ||||
| #ifdef DEBUG_PRINTF | ||||
|     printf("Non-mismatching seclen! %d, limit = %d\n", seclen_local, limit); | ||||
| #endif | ||||
|     seclen = seclen_local; | ||||
|     crc_val = ~0; | ||||
|     /* dump [secbuf .. secbuf+seclen) */ | ||||
|     if (pusi_seen) { | ||||
|       dvb_dmx_swfilter_section_feed(); | ||||
|     } | ||||
| #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||||
|     else | ||||
|       printf("dvb_demux.c pusi not seen, discarding section data\n"); | ||||
| #endif | ||||
|     secbufp += seclen_local;	/* secbufp and secbuf moving together is */ | ||||
|     secbuf += seclen_local;	/* redundant but saves pointer arithmetic */ | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| void cIptvSectionFilter::ProcessData(const uint8_t* buf) | ||||
| { | ||||
|   if (buf[0] != 0x47) { | ||||
|     error("Not TS packet: 0x%X\n", buf[0]); | ||||
|     return; | ||||
|   } | ||||
|    | ||||
|   // Stop if not the PID this filter is looking for | ||||
|   if (ts_pid(buf) != pid) | ||||
|     return; | ||||
|  | ||||
|   uint8_t count = payload(buf); | ||||
|  | ||||
|   if (count == 0)		/* count == 0 if no payload or out of range */ | ||||
|     return; | ||||
|  | ||||
|   uint8_t p = 188 - count;	/* payload start */ | ||||
|  | ||||
|   uint8_t cc = buf[3] & 0x0f; | ||||
|   int ccok = ((feedcc + 1) & 0x0f) == cc; | ||||
|   feedcc = cc;   | ||||
|  | ||||
|   int dc_i = 0; | ||||
|   if (buf[3] & 0x20) { | ||||
|     /* adaption field present, check for discontinuity_indicator */ | ||||
|     if ((buf[4] > 0) && (buf[5] & 0x80)) | ||||
|       dc_i = 1; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   if (!ccok || dc_i) { | ||||
| #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||||
|     printf("dvb_demux.c discontinuity detected %d bytes lost\n", | ||||
| 	   count); | ||||
|     /* | ||||
|      * those bytes under sume circumstances will again be reported | ||||
|      * in the following dvb_dmx_swfilter_section_new | ||||
|      */ | ||||
| #endif | ||||
|     /* | ||||
|      * Discontinuity detected. Reset pusi_seen = 0 to | ||||
|      * stop feeding of suspicious data until next PUSI=1 arrives | ||||
|      */ | ||||
|     pusi_seen = 0; | ||||
|     dvb_dmx_swfilter_section_new(); | ||||
|   } | ||||
|  | ||||
|   if (buf[1] & 0x40) { | ||||
|     /* PUSI=1 (is set), section boundary is here */ | ||||
|     if (count > 1 && buf[p] < count) { | ||||
| #ifdef DEBUG_PRINTF | ||||
|       printf("Valid section\n"); | ||||
| #endif | ||||
|       const uint8_t *before = &buf[p + 1]; | ||||
|       uint8_t before_len = buf[p]; | ||||
|       const uint8_t *after = &before[before_len]; | ||||
|       uint8_t after_len = count - 1 - before_len; | ||||
|  | ||||
|       dvb_dmx_swfilter_section_copy_dump(before, before_len); | ||||
|       /* before start of new section, set pusi_seen = 1 */ | ||||
|       pusi_seen = 1; | ||||
|       dvb_dmx_swfilter_section_new(); | ||||
|       dvb_dmx_swfilter_section_copy_dump(after, after_len); | ||||
|     } | ||||
| #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||||
|     else if (count > 0) | ||||
|       printf("dvb_demux.c PUSI=1 but %d bytes lost\n", count); | ||||
| #endif | ||||
|   } else { | ||||
|     /* PUSI=0 (is not set), no section boundary */ | ||||
|     dvb_dmx_swfilter_section_copy_dump(&buf[p], count); | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										117
									
								
								sectionfilter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								sectionfilter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| /* | ||||
|  * sectionfilter.h: IPTV plugin for the Video Disk Recorder | ||||
|  * | ||||
|  * See the README file for copyright information and how to reach the author. | ||||
|  * | ||||
|  * $Id: sectionfilter.h,v 1.1 2007/09/24 13:03:39 ajhseppa Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __IPTV_SECTIONFILTER_H | ||||
| #define __IPTV_SECTIONFILTER_H | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <libgen.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| #include <sys/param.h> | ||||
|  | ||||
| #include "common.h" | ||||
|  | ||||
| #ifndef DMX_MAX_FILTER_SIZE | ||||
| #define DMX_MAX_FILTER_SIZE 18 | ||||
| #endif | ||||
|  | ||||
| #ifndef DMX_MAX_SECTION_SIZE | ||||
| #define DMX_MAX_SECTION_SIZE 4096 | ||||
| #endif | ||||
| #ifndef DMX_MAX_SECFEED_SIZE | ||||
| #define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) | ||||
| #endif | ||||
|  | ||||
| #define DVB_DEMUX_MASK_MAX 18 | ||||
|  | ||||
| class cIptvSectionFilter { | ||||
|  | ||||
| private: | ||||
|    enum dmx_success { | ||||
|       DMX_OK = 0, /* Received Ok */ | ||||
|       DMX_LENGTH_ERROR, /* Incorrect length */ | ||||
|       DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ | ||||
|       DMX_CRC_ERROR, /* Incorrect CRC */ | ||||
|       DMX_FRAME_ERROR, /* Frame alignment error */ | ||||
|       DMX_FIFO_ERROR, /* Receiver FIFO overrun */ | ||||
|       DMX_MISSED_ERROR /* Receiver missed packet */ | ||||
|    } ; | ||||
|  | ||||
|    int fifoDescriptor; | ||||
|    int readDescriptor; | ||||
|  | ||||
|    int pusi_seen; | ||||
|    int feedcc; | ||||
|    int doneq; | ||||
|  | ||||
|    uint8_t *secbuf; | ||||
|    uint8_t secbuf_base[DMX_MAX_SECFEED_SIZE]; | ||||
|    uint16_t secbufp; | ||||
|    uint16_t seclen; | ||||
|    uint16_t tsfeedp; | ||||
|    uint32_t crc_val; | ||||
|  | ||||
|    uint16_t pid; | ||||
|    int id; | ||||
|  | ||||
|  | ||||
|    uint8_t filter_value[DMX_MAX_FILTER_SIZE]; | ||||
|    uint8_t filter_mask[DMX_MAX_FILTER_SIZE]; | ||||
|    uint8_t filter_mode[DMX_MAX_FILTER_SIZE]; | ||||
|     | ||||
|    uint8_t maskandmode[DMX_MAX_FILTER_SIZE]; | ||||
|    uint8_t maskandnotmode[DMX_MAX_FILTER_SIZE]; | ||||
|  | ||||
|    char pipeName[128]; | ||||
|  | ||||
|    inline uint16_t section_length(const uint8_t *buf); | ||||
|    inline uint16_t ts_pid(const uint8_t *buf); | ||||
|    inline uint8_t payload(const uint8_t *tsp); | ||||
|  | ||||
|    int dvb_dmxdev_section_callback(const uint8_t *buffer1, | ||||
|                                    size_t buffer1_len, | ||||
|                                    const uint8_t *buffer2, | ||||
|                                    size_t buffer2_len, | ||||
|                                    enum dmx_success success); | ||||
|  | ||||
|    void dvb_dmx_swfilter_section_new(); | ||||
|  | ||||
|    int dvb_dmx_swfilter_sectionfilter(); | ||||
|  | ||||
|    inline int dvb_dmx_swfilter_section_feed(); | ||||
|  | ||||
|    int dvb_dmx_swfilter_section_copy_dump(const uint8_t *buf, | ||||
|                                           uint8_t len); | ||||
|  | ||||
|    int GetFifoDesc(); | ||||
|    void ClearPipeName(); | ||||
|    void SetPipeName(int deviceIndex); | ||||
|  | ||||
| public: | ||||
|    // constructor & destructor | ||||
|    cIptvSectionFilter(int Index, int devInd, u_short Pid, u_char Tid, | ||||
|                       u_char Mask); | ||||
|  | ||||
|    virtual ~cIptvSectionFilter(); | ||||
|  | ||||
|    void ProcessData(const uint8_t* buf); | ||||
|  | ||||
|    int GetReadDesc(); | ||||
| }; | ||||
|  | ||||
| #endif // __IPTV_SECTIONFILTER_H | ||||
|  | ||||
		Reference in New Issue
	
	Block a user