]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
mpegts: optimize the data patch (join MPEG-TS packets for processing)
authorJaroslav Kysela <perex@perex.cz>
Mon, 16 Mar 2015 20:46:11 +0000 (21:46 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 17 Mar 2015 08:52:53 +0000 (09:52 +0100)
src/descrambler.h
src/descrambler/descrambler.c
src/descrambler/tvhcsa.c
src/descrambler/tvhcsa.h
src/input/mpegts.h
src/input/mpegts/mpegts_input.c
src/input/mpegts/tsdemux.c
src/input/mpegts/tsdemux.h
src/tvh_endian.h [new file with mode: 0644]
src/tvheadend.h
src/utils.c

index 8ce3e98e12f77713c4f3185fc89cc40bfdecee02..10552023c3ee52e1e4da7fa59009e653a2c6ab90 100644 (file)
@@ -167,7 +167,7 @@ void descrambler_keys          ( th_descrambler_t *t, int type,
                                  const uint8_t *even, const uint8_t *odd );
 int  descrambler_descramble    ( struct service *t,
                                  struct elementary_stream *st,
-                                 const uint8_t *tsb );
+                                 const uint8_t *tsb, int len );
 int  descrambler_open_pid      ( struct mpegts_mux *mux, void *opaque, int pid,
                                  descrambler_section_callback_t callback,
                                  struct service *service );
index 8918fd6bfa2672a8482296e575457e6bbe52ba60..737a688250c2937e0f13b163be859a9834358b95 100644 (file)
@@ -367,18 +367,20 @@ ecm_reset( service_t *t, th_descrambler_runtime_t *dr )
 int
 descrambler_descramble ( service_t *t,
                          elementary_stream_t *st,
-                         const uint8_t *tsb )
+                         const uint8_t *tsb,
+                         int len )
 {
   th_descrambler_t *td;
   th_descrambler_runtime_t *dr = t->s_descramble;
-  int count, failed, resolved, off, size, flush_data = 0;
-  uint8_t *tsb2, ki;
+  int count, failed, resolved, off, len2, len3, flush_data = 0;
+  const uint8_t *tsb2;
+  uint8_t ki;
 
   lock_assert(&t->s_stream_mutex);
 
   if (dr == NULL) {
     if ((tsb[3] & 0x80) == 0) {
-      ts_recv_packet2((mpegts_service_t *)t, tsb);
+      ts_recv_packet2((mpegts_service_t *)t, tsb, len);
       return 1;
     }
     return -1;
@@ -386,7 +388,7 @@ descrambler_descramble ( service_t *t,
 
   if (dr->dr_csa.csa_type == DESCRAMBLER_NONE && dr->dr_buf.sb_ptr == 0)
     if ((tsb[3] & 0x80) == 0) {
-      ts_recv_packet2((mpegts_service_t *)t, tsb);
+      ts_recv_packet2((mpegts_service_t *)t, tsb, len);
       return 1;
     }
 
@@ -414,12 +416,11 @@ descrambler_descramble ( service_t *t,
 
     /* process the queued TS packets */
     if (dr->dr_buf.sb_ptr > 0) {
-      for (off = 0, size = dr->dr_buf.sb_ptr; off < size; off += 188) {
-        tsb2 = dr->dr_buf.sb_data + off;
+      for (tsb2 = tsb, len2 = dr->dr_buf.sb_ptr; len2 > 0; tsb2 += len3, len2 -= len3) {
         ki = tsb2[3];
         if ((ki & 0x80) != 0x00) {
           if (key_valid(dr, ki) == 0) {
-            sbuf_cut(&dr->dr_buf, off);
+            sbuf_cut(&dr->dr_buf, tsb2 - tsb);
             flush_data = 1;
             goto next;
           }
@@ -429,8 +430,8 @@ descrambler_descramble ( service_t *t,
                                     (ki & 0x40) ? "odd" : "even",
                                     ((mpegts_service_t *)t)->s_dvb_svcname);
             if (key_late(dr, ki)) {
-              sbuf_cut(&dr->dr_buf, off);
               if (ecm_reset(t, dr)) {
+                sbuf_cut(&dr->dr_buf, tsb2 - tsb);
                 flush_data = 1;
                 goto next;
               }
@@ -438,9 +439,10 @@ descrambler_descramble ( service_t *t,
             key_update(dr, ki);
           }
         }
-        dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb2);
+        len3 = mpegts_word_count(tsb2, len2, 0xFF0000C0);
+        dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb2, len3);
       }
-      if (off > 0)
+      if (len2 == 0)
         service_reset_streaming_status_flags(t, TSS_NO_ACCESS);
       sbuf_free(&dr->dr_buf);
     }
@@ -473,7 +475,7 @@ descrambler_descramble ( service_t *t,
         key_update(dr, ki);
       }
     }
-    dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb);
+    dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb, len);
     service_reset_streaming_status_flags(t, TSS_NO_ACCESS);
     return 1;
   }
@@ -520,7 +522,7 @@ next:
                    ((mpegts_service_t *)t)->s_dvb_svcname);
         }
       }
-      sbuf_append(&dr->dr_buf, tsb, 188);
+      sbuf_append(&dr->dr_buf, tsb, len);
       service_set_streaming_status_flags(t, TSS_NO_ACCESS);
     }
   } else {
index a10480f79e68569046305da4ea486a11b4693213..99ff46a018d1fb963031ed4412462d98a111e39a 100644 (file)
@@ -33,10 +33,13 @@ tvhcsa_aes_flush
 
 static void
 tvhcsa_aes_descramble
-  ( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb )
+  ( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb, int len )
 {
-  aes_decrypt_packet(csa->csa_aes_keys, (unsigned char *)tsb);
-  ts_recv_packet2(s, tsb);
+  const uint8_t *tsb2, *end2;
+
+  for (tsb2 = tsb, end2 = tsb + len; tsb2 < end2; tsb2 += 188)
+    aes_decrypt_packet(csa->csa_aes_keys, (unsigned char *)tsb2);
+  ts_recv_packet2(s, tsb, len);
 }
 
 static void
@@ -45,9 +48,6 @@ tvhcsa_des_flush
 {
 #if ENABLE_DVBCSA
 
-  int i;
-  const uint8_t *t0;
-
   if(csa->csa_fill_even) {
     csa->csa_tsbbatch_even[csa->csa_fill_even].data = NULL;
     dvbcsa_bs_decrypt(csa->csa_key_even, csa->csa_tsbbatch_even, 184);
@@ -59,45 +59,31 @@ tvhcsa_des_flush
     csa->csa_fill_odd = 0;
   }
 
-  t0 = csa->csa_tsbcluster;
+  ts_recv_packet2(s, csa->csa_tsbcluster, csa->csa_fill * 188);
 
-  for(i = 0; i < csa->csa_fill; i++) {
-    ts_recv_packet2(s, t0);
-    t0 += 188;
-  }
   csa->csa_fill = 0;
 
 #else
 
-  int r;
+  int r, l;
   unsigned char *vec[3];
 
-  while(1) {
+  vec[0] = csa->csa_tsbcluster;
+  vec[1] = csa->csa_tsbcluster + csa->csa_fill * 188;
+  vec[2] = NULL;
 
-    vec[0] = csa->csa_tsbcluster;
-    vec[1] = csa->csa_tsbcluster + csa->csa_fill * 188;
-    vec[2] = NULL;
+  r = decrypt_packets(csa->csa_keys, vec);
+  if(r > 0) {
+    ts_recv_packet2(s, csa->csa_tsbcluster, r * 188);
 
-    r = decrypt_packets(csa->csa_keys, vec);
-    if(r > 0) {
-      int i;
-      const uint8_t *t0 = csa->csa_tsbcluster;
+    l = csa->csa_fill - r;
+    assert(l >= 0);
 
-      for(i = 0; i < r; i++) {
-        ts_recv_packet2(s, t0);
-        t0 += 188;
-      }
-
-      r = csa->csa_fill - r;
-      assert(r >= 0);
-
-      if(r > 0)
-        memmove(csa->csa_tsbcluster, t0, r * 188);
-      csa->csa_fill = r;
-    } else {
-      csa->csa_fill = 0;
-    }
-    break;
+    if(l > 0)
+      memmove(csa->csa_tsbcluster, csa->csa_tsbcluster + r * 188, l * 188);
+    csa->csa_fill = l;
+  } else {
+    csa->csa_fill = 0;
   }
 
 #endif
@@ -105,8 +91,10 @@ tvhcsa_des_flush
 
 static void
 tvhcsa_des_descramble
-  ( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb )
+  ( tvhcsa_t *csa, struct mpegts_service *s, const uint8_t *tsb, int tsb_len )
 {
+  const uint8_t *tsb_end = tsb + tsb_len;
+
   assert(csa->csa_fill >= 0 && csa->csa_fill < csa->csa_cluster_size);
 
 #if ENABLE_DVBCSA
@@ -117,61 +105,65 @@ tvhcsa_des_descramble
   int offset;
   int n;
 
-  pkt = csa->csa_tsbcluster + csa->csa_fill * 188;
-  memcpy(pkt, tsb, 188);
-  csa->csa_fill++;
-
-  do { // handle this packet
-    xc0 = pkt[3] & 0xc0;
-    if(xc0 == 0x00) { // clear
-      break;
-    }
-    if(xc0 == 0x40) { // reserved
-      break;
-    }
-    if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
-      ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
-      pkt[3] &= 0x3f;  // consider it decrypted now
-      if(pkt[3] & 0x20) { // incomplete packet
-        offset = 4 + pkt[4] + 1;
-        len = 188 - offset;
-        n = len >> 3;
-        // FIXME: //residue = len - (n << 3);
-        if(n == 0) { // decrypted==encrypted!
-          break; // this doesn't need more processing
-        }
-      } else {
-        len = 184;
-        offset = 4;
-        // FIXME: //n = 23;
-        // FIXME: //residue = 0;
-      }
-      if(ev_od == 0) {
-        csa->csa_tsbbatch_even[csa->csa_fill_even].data = pkt + offset;
-        csa->csa_tsbbatch_even[csa->csa_fill_even].len = len;
-        csa->csa_fill_even++;
-      } else {
-        csa->csa_tsbbatch_odd[csa->csa_fill_odd].data = pkt + offset;
-        csa->csa_tsbbatch_odd[csa->csa_fill_odd].len = len;
-        csa->csa_fill_odd++;
-      }
-    }
-  } while(0);
-
-  if(csa->csa_fill != csa->csa_cluster_size)
-    return;
-
-  tvhcsa_des_flush(csa, s);
+  for ( ; tsb < tsb_end; tsb += 188) {
+
+   pkt = csa->csa_tsbcluster + csa->csa_fill * 188;
+   memcpy(pkt, tsb, 188);
+   csa->csa_fill++;
+
+   do { // handle this packet
+     xc0 = pkt[3] & 0xc0;
+     if(xc0 == 0x00) { // clear
+       break;
+     }
+     if(xc0 == 0x40) { // reserved
+       break;
+     }
+     if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
+       ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
+       pkt[3] &= 0x3f;  // consider it decrypted now
+       if(pkt[3] & 0x20) { // incomplete packet
+         offset = 4 + pkt[4] + 1;
+         len = 188 - offset;
+         n = len >> 3;
+         // FIXME: //residue = len - (n << 3);
+         if(n == 0) { // decrypted==encrypted!
+           break; // this doesn't need more processing
+         }
+       } else {
+         len = 184;
+         offset = 4;
+         // FIXME: //n = 23;
+         // FIXME: //residue = 0;
+       }
+       if(ev_od == 0) {
+         csa->csa_tsbbatch_even[csa->csa_fill_even].data = pkt + offset;
+         csa->csa_tsbbatch_even[csa->csa_fill_even].len = len;
+         csa->csa_fill_even++;
+       } else {
+         csa->csa_tsbbatch_odd[csa->csa_fill_odd].data = pkt + offset;
+         csa->csa_tsbbatch_odd[csa->csa_fill_odd].len = len;
+         csa->csa_fill_odd++;
+       }
+     }
+   } while(0);
+
+   if(csa->csa_fill == csa->csa_cluster_size)
+     tvhcsa_des_flush(csa, s);
+
+  }
 
 #else
 
-  memcpy(csa->csa_tsbcluster + csa->csa_fill * 188, tsb, 188);
-  csa->csa_fill++;
+  for ( ; tsb < tsb_end; tsb += 188 ) {
 
-  if(csa->csa_fill != csa->csa_cluster_size)
-    return;
+    memcpy(csa->csa_tsbcluster + csa->csa_fill * 188, tsb, 188);
+    csa->csa_fill++;
 
-  tvhcsa_des_flush(csa, s);
+    if(csa->csa_fill == csa->csa_cluster_size)
+      tvhcsa_des_flush(csa, s);
+
+  }
 
 #endif
 }
index 4a2b61467c9863d179b8b29ec58466966fb44d06..46950ddcc2bc76db08bf5a3f48a202cff7c0efac 100644 (file)
@@ -41,7 +41,8 @@ typedef struct tvhcsa
   int      csa_type;   /*< see DESCRAMBLER_* defines */
   int      csa_keylen;
   void   (*csa_descramble)
-              ( struct tvhcsa *csa, struct mpegts_service *s, const uint8_t *tsb );
+              ( struct tvhcsa *csa, struct mpegts_service *s,
+                const uint8_t *tsb, int len );
   void   (*csa_flush)
               ( struct tvhcsa *csa, struct mpegts_service *s );
 
index 8246d4350c2cd04d1956fd4991b0c1d628c291a1..850d652b7ba58b0caa7f6b1c166333d4934d8c34 100644 (file)
@@ -262,8 +262,9 @@ struct mpegts_table
 
 struct mpegts_table_feed {
   TAILQ_ENTRY(mpegts_table_feed) mtf_link;
-  uint8_t mtf_tsb[188];
+  int mtf_len;
   mpegts_mux_t *mtf_mux;
+  uint8_t mtf_tsb[0];
 };
 
 /*
index 5b63864bce4dde9f90fb7eba34acf18e805a520d..85a57fa43b1fc0daf44a229f7ba9a13d6ec273b3 100644 (file)
@@ -875,7 +875,7 @@ mpegts_input_recv_packets
     for (tmp = tsb, end = tsb + p * 188; tmp < end; tmp += 188) {
       uint16_t pid = ((tmp[1] & 0x1f) << 8) | tmp[2];
       if (*pcr_pid == MPEGTS_PID_NONE || *pcr_pid == pid) {
-        ts_recv_packet1(NULL, tmp, pcr, 0);
+        ts_recv_packet1(NULL, tmp, 188, pcr, 0);
        if (*pcr != PTS_UNSET) *pcr_pid = pid;
       }
     }
@@ -911,20 +911,20 @@ mpegts_input_recv_packets
 }
 
 static void
-mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb )
+mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb, int tsb_len )
 {
   int i, len = 0, c = 0;
+  const uint8_t *tsb2, *tsb2_end;
   uint16_t pid = ((tsb[1] & 0x1f) << 8) | tsb[2];
-  uint8_t  cc  = (tsb[3] & 0x0f);
   mpegts_table_t *mt, **vec;
 
   /* Collate - tables may be removed during callbacks */
-  pthread_mutex_lock(&mm->mm_tables_lock);
   i = mm->mm_num_tables;
   vec = alloca(i * sizeof(mpegts_table_t *));
+  pthread_mutex_lock(&mm->mm_tables_lock);
   LIST_FOREACH(mt, &mm->mm_tables, mt_link) {
     c++;
-    if (mt->mt_destroyed || !mt->mt_subscribed)
+    if (mt->mt_destroyed || !mt->mt_subscribed || mt->mt_pid != pid)
       continue;
     mpegts_table_grab(mt);
     if (len < i)
@@ -939,20 +939,22 @@ mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb )
   /* Process */
   for (i = 0; i < len; i++) {
     mt = vec[i];
-    if (!mt->mt_destroyed && mt->mt_pid == pid) {
-      if (tsb[3] & 0x10) {
-        int ccerr = 0;
-        if (mt->mt_cc != -1 && mt->mt_cc != cc) {
-          ccerr = 1;
-          /* Ignore dupes (shouldn't have payload set, but some seem to) */
-          //if (((mt->mt_cc + 15) & 0xf) != cc)
-          tvhdebug("psi", "PID %04X CC error %d != %d", pid, cc, mt->mt_cc);
-         }
-        mt->mt_cc = (cc + 1) & 0xF;
-        mpegts_psi_section_reassemble(&mt->mt_sect, tsb, 0, ccerr,
-                                      mpegts_table_dispatch, mt);
+    if (!mt->mt_destroyed && mt->mt_pid == pid)
+      for (tsb2 = tsb, tsb2_end = tsb + tsb_len; tsb2 < tsb2_end; tsb2 += 188) {
+        uint8_t cc = tsb2[3];
+        if (cc & 0x10) {
+          int ccerr = 0;
+          if (mt->mt_cc != -1 && mt->mt_cc != (cc & 0xF)) {
+            ccerr = 1;
+            /* Ignore dupes (shouldn't have payload set, but some seem to) */
+            //if (((mt->mt_cc + 15) & 0xf) != cc)
+            tvhdebug("psi", "PID %04X CC error %d != %d", pid, cc, mt->mt_cc);
+          }
+          mt->mt_cc = (cc + 1) & 0xF;
+          mpegts_psi_section_reassemble(&mt->mt_sect, tsb2, 0, ccerr,
+                                        mpegts_table_dispatch, mt);
+        }
       }
-    }
     mpegts_table_release(mt);
   }
 }
@@ -998,32 +1000,34 @@ mpegts_input_table_waiting ( mpegts_input_t *mi, mpegts_mux_t *mm )
 
 #if ENABLE_TSDEBUG
 static void
-tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt )
+tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt, int len )
 {
   void tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even);
   uint32_t pos, type, keylen, sid, crc;
   mpegts_service_t *t;
 
-  if (memcmp(pkt + 4, "TVHeadendDescramblerKeys", 24))
-    return;
-  pos = 4 + 24;
-  type = pkt[pos + 0];
-  keylen = pkt[pos + 1];
-  sid = (pkt[pos + 2] << 8) | pkt[pos + 3];
-  pos += 4 + 2 * keylen;
-  if (pos > 184)
-    return;
-  crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) |
-        (pkt[pos + 2] << 8) | pkt[pos + 3];
-  if (crc != tvh_crc32(pkt, pos, 0x859aa5ba))
-    return;
-  LIST_FOREACH(t, &mm->mm_services, s_dvb_mux_link)
-    if (t->s_dvb_service_id == sid) break;
-  if (!t)
-    return;
-  pos =  4 + 24 + 4;
-  tvhdebug("descrambler", "Keys from MPEG-TS source (PID 0x1FFF)!");
-  tsdebugcw_new_keys((service_t *)t, type, pkt + pos, pkt + pos + keylen);
+  for ( ; len > 0; pkt += 188, len -= 188) {
+    if (memcmp(pkt + 4, "TVHeadendDescramblerKeys", 24))
+      continue;
+    pos = 4 + 24;
+    type = pkt[pos + 0];
+    keylen = pkt[pos + 1];
+    sid = (pkt[pos + 2] << 8) | pkt[pos + 3];
+    pos += 4 + 2 * keylen;
+    if (pos > 184)
+      return;
+    crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) |
+          (pkt[pos + 2] << 8) | pkt[pos + 3];
+    if (crc != tvh_crc32(pkt, pos, 0x859aa5ba))
+      return;
+    LIST_FOREACH(t, &mm->mm_services, s_dvb_mux_link)
+      if (t->s_dvb_service_id == sid) break;
+    if (!t)
+      return;
+    pos =  4 + 24 + 4;
+    tvhdebug("descrambler", "Keys from MPEG-TS source (PID 0x1FFF)!");
+    tsdebugcw_new_keys((service_t *)t, type, pkt + pos, pkt + pos + keylen);
+  }
 }
 #endif
 
@@ -1034,14 +1038,13 @@ mpegts_input_process
   uint16_t pid;
   uint8_t cc;
   uint8_t *tsb = mpkt->mp_data;
-  int len = mpkt->mp_len;
+  int len = mpkt->mp_len, llen;
   int type = 0, f;
   mpegts_pid_t *mp;
   mpegts_pid_sub_t *mps;
   service_t *s;
   int table_wakeup = 0;
-  uint8_t *end = mpkt->mp_data + len;
-  mpegts_mux_t          *mm  = mpkt->mp_mux;
+  mpegts_mux_t *mm = mpkt->mp_mux;
   mpegts_mux_instance_t *mmi;
 #if ENABLE_TSDEBUG
   off_t tsdebug_pos;
@@ -1058,7 +1061,19 @@ mpegts_input_process
 
   /* Process */
   assert((len % 188) == 0);
-  while (tsb < end) {
+  while (len > 0) {
+
+    /*
+     * mask
+     *  0 - 0xFF - sync word 0x47
+     *  1 - 0x80 - transport error
+     *  1 - 0x1F - pid high
+     *  2 - 0xFF - pid low
+     *  3 - 0xC0 - scrambled
+     *  3 - 0x10 - CC check
+     */
+    llen = mpegts_word_count(tsb, len, 0xFF9FFFD0);
+
     pid = (tsb[1] << 8) | tsb[2];
     cc  = tsb[3];
 
@@ -1073,7 +1088,7 @@ mpegts_input_process
     /* Ignore NUL packets */
     if (pid == 0x1FFF) {
 #if ENABLE_TSDEBUG
-      tsdebug_check_tspkt(mm, tsb);
+      tsdebug_check_tspkt(mm, tsb, llen);
 #endif
       goto done;
     }
@@ -1096,12 +1111,12 @@ mpegts_input_process
       /* Stream all PIDs */
       LIST_FOREACH(mps, &mm->mm_all_subs, mps_svcraw_link)
         if ((mps->mps_type & MPS_ALL) || (type & (MPS_TABLE|MPS_FTABLE)))
-          ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb);
+          ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb, llen);
 
       /* Stream raw PIDs */
       if (type & MPS_RAW) {
         LIST_FOREACH(mps, &mp->mp_svc_subs, mps_svcraw_link)
-          ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb);
+          ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb, llen);
       }
 
       /* Stream service data */
@@ -1110,7 +1125,7 @@ mpegts_input_process
           s = mps->mps_owner;
           f = (type & (MPS_TABLE|MPS_FTABLE)) ||
               (pid == s->s_pmt_pid) || (pid == s->s_pcr_pid);
-          ts_recv_packet1((mpegts_service_t*)s, tsb, NULL, f);
+          ts_recv_packet1((mpegts_service_t*)s, tsb, llen, NULL, f);
         }
       } else
       /* Stream table data */
@@ -1119,7 +1134,7 @@ mpegts_input_process
           if (s->s_type != STYPE_STD) continue;
           f = (type & (MPS_TABLE|MPS_FTABLE)) ||
               (pid == s->s_pmt_pid) || (pid == s->s_pcr_pid);
-          ts_recv_packet1((mpegts_service_t*)s, tsb, NULL, f);
+          ts_recv_packet1((mpegts_service_t*)s, tsb, llen, NULL, f);
         }
       }
 
@@ -1127,14 +1142,12 @@ mpegts_input_process
       if (type & (MPS_TABLE | MPS_FTABLE)) {
         if (!(tsb[1] & 0x80)) {
           if (type & MPS_FTABLE)
-            mpegts_input_table_dispatch(mm, tsb);
+            mpegts_input_table_dispatch(mm, tsb, llen);
           if (type & MPS_TABLE) {
-            // TODO: might be able to optimise this a bit by having slightly
-            //       larger buffering and trying to aggregate data (if we get
-            //       same PID multiple times in the loop)
-            mpegts_table_feed_t *mtf = malloc(sizeof(mpegts_table_feed_t));
-            memcpy(mtf->mtf_tsb, tsb, 188);
-            mtf->mtf_mux   = mm;
+            mpegts_table_feed_t *mtf = malloc(sizeof(mpegts_table_feed_t)+llen);
+            mtf->mtf_len = llen;
+            memcpy(mtf->mtf_tsb, tsb, llen);
+            mtf->mtf_mux = mm;
             TAILQ_INSERT_TAIL(&mi->mi_table_queue, mtf, mtf_link);
             table_wakeup = 1;
           }
@@ -1147,14 +1160,15 @@ mpegts_input_process
 
       /* Stream to all fullmux subscribers */
       LIST_FOREACH(mps, &mm->mm_all_subs, mps_svcraw_link)
-        ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb);
+        ts_recv_raw((mpegts_service_t *)mps->mps_owner, tsb, llen);
 
     }
 
 done:
-    tsb += 188;
+    tsb += llen;
+    len -= llen;
 #if ENABLE_TSDEBUG
-    mm->mm_tsdebug_pos += 188;
+    mm->mm_tsdebug_pos += llen;
 #endif
   }
 
@@ -1266,7 +1280,7 @@ mpegts_input_table_thread ( void *aux )
     /* Process */
     pthread_mutex_lock(&global_lock);
     if (mtf->mtf_mux && mtf->mtf_mux->mm_active)
-      mpegts_input_table_dispatch(mtf->mtf_mux, mtf->mtf_tsb);
+      mpegts_input_table_dispatch(mtf->mtf_mux, mtf->mtf_tsb, mtf->mtf_len);
     pthread_mutex_unlock(&global_lock);
 
     /* Cleanup */
index 2db7720f3f672a02b1125e5900fc826683b1a58c..a5c04610a1f0197c040b53280d2b6c6217355aa8 100644 (file)
 
 #define TS_REMUX_BUFSIZE (188 * 100)
 
-static void ts_remux(mpegts_service_t *t, const uint8_t *tsb, int error);
+static void ts_remux(mpegts_service_t *t, const uint8_t *tsb, int len, int error);
 
 /**
  * Continue processing of transport stream packets
  */
 static void
 ts_recv_packet0
-  (mpegts_service_t *t, elementary_stream_t *st, const uint8_t *tsb)
+  (mpegts_service_t *t, elementary_stream_t *st, const uint8_t *tsb, int len)
 {
   mpegts_service_t *m;
   int off, pusi, cc, error;
@@ -58,53 +58,58 @@ ts_recv_packet0
 
   if (!st) {
     if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
-      ts_remux(t, tsb, 0);
+      ts_remux(t, tsb, len, 0);
     return;
   }
 
   error = !!(tsb[1] & 0x80);
-  pusi  = !!(tsb[1] & 0x40);
-
-  /* Check CC */
-
-  if(tsb[3] & 0x10) {
-    cc = tsb[3] & 0xf;
-    if(st->es_cc != -1 && cc != st->es_cc) {
-      /* Let the hardware to stabilize and don't flood the log */
-      if (t->s_start_time + 1 < dispatch_clock &&
-          tvhlog_limit(&st->es_cc_log, 10))
-        tvhwarn("TS", "%s Continuity counter error (total %zi)",
-                      service_component_nicename(st), st->es_cc_log.count);
-      avgstat_add(&t->s_cc_errors, 1, dispatch_clock);
-      avgstat_add(&st->es_cc_errors, 1, dispatch_clock);
-      error |= 2;
-    }
-    st->es_cc = (cc + 1) & 0xf;
-  }
 
   if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
-    ts_remux(t, tsb, error);
+    ts_remux(t, tsb, len, error);
 
   LIST_FOREACH(m, &t->s_masters, s_masters_link) {
     pthread_mutex_lock(&m->s_stream_mutex);
     if(streaming_pad_probe_type(&m->s_streaming_pad, SMT_MPEGTS))
-      ts_remux(m, tsb, error);
+      ts_remux(m, tsb, len, error);
     pthread_mutex_unlock(&m->s_stream_mutex);
   }
 
-  off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
+  for ( ; len > 0; tsb += 188, len -= 188) {
 
-  if (st->es_type == SCT_CA)
-    return;
+    pusi  = !!(tsb[1] & 0x40);
 
-  if(!streaming_pad_probe_type(&t->s_streaming_pad, SMT_PACKET))
-    return;
+    /* Check CC */
+
+    if(tsb[3] & 0x10) {
+      cc = tsb[3] & 0xf;
+      if(st->es_cc != -1 && cc != st->es_cc) {
+        /* Let the hardware to stabilize and don't flood the log */
+        if (t->s_start_time + 1 < dispatch_clock &&
+            tvhlog_limit(&st->es_cc_log, 10))
+          tvhwarn("TS", "%s Continuity counter error (total %zi)",
+                        service_component_nicename(st), st->es_cc_log.count);
+        avgstat_add(&t->s_cc_errors, 1, dispatch_clock);
+        avgstat_add(&st->es_cc_errors, 1, dispatch_clock);
+        error |= 2;
+      }
+      st->es_cc = (cc + 1) & 0xf;
+    }
 
-  if(st->es_type == SCT_TELETEXT)
-    teletext_input(t, st, tsb);
+    off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
 
-  if(off <= 188 && t->s_status == SERVICE_RUNNING)
-    parse_mpeg_ts((service_t*)t, st, tsb + off, 188 - off, pusi, error);
+    if (st->es_type == SCT_CA)
+      continue;
+
+    if(!streaming_pad_probe_type(&t->s_streaming_pad, SMT_PACKET))
+      continue;
+
+    if(st->es_type == SCT_TELETEXT)
+      teletext_input(t, st, tsb);
+
+    if(off <= 188 && t->s_status == SERVICE_RUNNING)
+      parse_mpeg_ts((service_t*)t, st, tsb + off, 188 - off, pusi, error);
+
+  }
 }
 
 /**
@@ -112,7 +117,7 @@ ts_recv_packet0
  */
 int
 ts_recv_packet1
-  (mpegts_service_t *t, const uint8_t *tsb, int64_t *pcrp, int table)
+  (mpegts_service_t *t, const uint8_t *tsb, int len, int64_t *pcrp, int table)
 {
   elementary_stream_t *st;
   int pid, r;
@@ -168,7 +173,7 @@ ts_recv_packet1
   if(!error)
     service_set_streaming_status_flags((service_t*)t, TSS_INPUT_SERVICE);
 
-  avgstat_add(&t->s_rate, 188, dispatch_clock);
+  avgstat_add(&t->s_rate, len, dispatch_clock);
 
   if((tsb[3] & 0xc0) ||
       (t->s_scrambled_seen && st && st->es_type != SCT_CA)) {
@@ -180,7 +185,7 @@ ts_recv_packet1
       t->s_scrambled_seen |= service_is_encrypted((service_t*)t);
 
     /* scrambled stream */
-    r = descrambler_descramble((service_t *)t, st, tsb);
+    r = descrambler_descramble((service_t *)t, st, tsb, len);
     if(r > 0) {
       pthread_mutex_unlock(&t->s_stream_mutex);
       return 1;
@@ -195,7 +200,7 @@ ts_recv_packet1
     }
 
   } else {
-    ts_recv_packet0(t, st, tsb);
+    ts_recv_packet0(t, st, tsb, len);
   }
   pthread_mutex_unlock(&t->s_stream_mutex);
   return 1;
@@ -206,20 +211,24 @@ ts_recv_packet1
  * Process transport stream packets, simple version
  */
 void
-ts_recv_packet2(mpegts_service_t *t, const uint8_t *tsb)
+ts_recv_packet2(mpegts_service_t *t, const uint8_t *tsb, int len)
 {
   elementary_stream_t *st;
-  int pid = (tsb[1] & 0x1f) << 8 | tsb[2];
+  int pid, len2;
 
-  if((st = service_stream_find((service_t*)t, pid)) != NULL)
-    ts_recv_packet0(t, st, tsb);
+  for ( ; len > 0; tsb += len2, len -= len2 ) {
+    len2 = mpegts_word_count(tsb, len, 0xFF9FFFD0);
+    pid = (tsb[1] & 0x1f) << 8 | tsb[2];
+    if((st = service_stream_find((service_t*)t, pid)) != NULL)
+      ts_recv_packet0(t, st, tsb, len2);
+  }
 }
 
 /*
  *
  */
 void
-ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb)
+ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb, int len)
 {
   int pid, parent = 0;
 
@@ -236,7 +245,7 @@ ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb)
   }
   if(!parent) {
     if (streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
-      ts_remux(t, tsb, 0);
+      ts_remux(t, tsb, len, 0);
     else {
       /* No subscriber - set OK markers */
       service_set_streaming_status_flags((service_t*)t, TSS_PACKETS);
@@ -250,7 +259,7 @@ ts_recv_raw(mpegts_service_t *t, const uint8_t *tsb)
  *
  */
 static void
-ts_remux(mpegts_service_t *t, const uint8_t *src, int error)
+ts_remux(mpegts_service_t *t, const uint8_t *src, int len, int error)
 {
   streaming_message_t sm;
   pktbuf_t *pb;
@@ -259,7 +268,7 @@ ts_remux(mpegts_service_t *t, const uint8_t *src, int error)
   if (sb->sb_data == NULL)
     sbuf_init_fixed(sb, TS_REMUX_BUFSIZE);
 
-  sbuf_append(sb, src, 188);
+  sbuf_append(sb, src, len);
 
   if (error)
     sb->sb_err++;
@@ -279,7 +288,7 @@ ts_remux(mpegts_service_t *t, const uint8_t *src, int error)
   service_set_streaming_status_flags((service_t*)t, TSS_PACKETS);
   t->s_streaming_live |= TSS_LIVE;
 
-  sbuf_reset(sb, TS_REMUX_BUFSIZE);
+  sbuf_reset(sb, 2*TS_REMUX_BUFSIZE);
 }
 
 /*
index 74d19eca019840fbbf9381daabaee7d1920258b1..22296800f3c5c99c41824bda8be2804d139c9999 100644 (file)
 int ts_resync ( const uint8_t *tsb, int *len, int *idx );
 
 int ts_recv_packet1
-  (struct mpegts_service *t, const uint8_t *tsb, int64_t *pcrp, int table);
+  (struct mpegts_service *t, const uint8_t *tsb, int len, int64_t *pcrp, int table);
 
-void ts_recv_packet2(struct mpegts_service *t, const uint8_t *tsb);
+void ts_recv_packet2(struct mpegts_service *t, const uint8_t *tsb, int len);
 
-void ts_recv_raw(struct mpegts_service *t, const uint8_t *tsb);
+void ts_recv_raw(struct mpegts_service *t, const uint8_t *tsb, int len);
 
 #endif /* TSDEMUX_H */
diff --git a/src/tvh_endian.h b/src/tvh_endian.h
new file mode 100644 (file)
index 0000000..588bd8a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 Jaroslav Kysela <perex@perex.cz>
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TVH_ENDIAN_H
+#define __TVH_ENDIAN_H
+
+#include <byteswap.h>
+#if defined(PLATFORM_DARWIN)
+#include <machine/endian.h>
+#elif defined(PLATFORM_FREEBSD)
+#include <sys/endian.h>
+#else
+#include <endian.h>
+#endif
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER __BYTE_ORDER
+#endif
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN __BIG_ENDIAN
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ENDIAN_SWAP_COND(x) (!(x))
+#else
+#define ENDIAN_SWAP_COND(x) (x)
+#endif
+
+#endif /* __TVH_ENDIAN_H */
index a4b04f4efffac1b0d863107ef8b5dd0a751f2f3a..2a281fd92dd030844d1ce085ddd2daef800c23d3 100644 (file)
@@ -716,6 +716,8 @@ char *regexp_escape ( const char *str );
 char to_hex(char code);
 char *url_encode(char *str);
 
+int mpegts_word_count(const uint8_t *tsb, int len, uint32_t mask);
+
 static inline int32_t deltaI32(int32_t a, int32_t b) { return (a > b) ? (a - b) : (b - a); }
 static inline uint32_t deltaU32(uint32_t a, uint32_t b) { return (a > b) ? (a - b) : (b - a); }
   
index 92d309fc58d25f0d7f67f6afedb9eedc9e15b096..845bfa4d6193fa47e272b4fbe1bc77b160f5ebbb 100644 (file)
 #include <unistd.h>
 #include <ctype.h>
 #include "tvheadend.h"
-
-#if defined(PLATFORM_DARWIN)
-#include <machine/endian.h>
-#elif defined(PLATFORM_FREEBSD)
-#include <sys/endian.h>
-#else
-#include <endian.h>
-#endif
-
-#ifndef BYTE_ORDER
-#define BYTE_ORDER __BYTE_ORDER
-#endif
-#ifndef LITTLE_ENDIAN
-#define LITTLE_ENDIAN __LITTLE_ENDIAN
-#endif
-#ifndef BIG_ENDIAN
-#define BIG_ENDIAN __BIG_ENDIAN
-#endif
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define ENDIAN_SWAP_COND(x) (!(x))
-#else
-#define ENDIAN_SWAP_COND(x) (x)
-#endif
+#include "tvh_endian.h"
 
 /**
  * CRC32 
@@ -615,3 +593,45 @@ char *url_encode(char *str) {
   return buf;
 }
 
+/*
+ *
+ */
+
+static inline uint32_t mpegts_word32( const uint8_t *tsb )
+{
+  //assert(((intptr_t)tsb & 3) == 0);
+  return *(uint32_t *)tsb;
+}
+
+int
+mpegts_word_count ( const uint8_t *tsb, int len, uint32_t mask )
+{
+  uint32_t val;
+  int r = 0;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+  mask = bswap_32(mask);
+#endif
+
+  val  = mpegts_word32(tsb) & mask;
+
+  while (len >= 188) {
+    if (len >= 4*188 &&
+        (mpegts_word32(tsb+0*188) & mask) == val &&
+        (mpegts_word32(tsb+1*188) & mask) == val &&
+        (mpegts_word32(tsb+2*188) & mask) == val &&
+        (mpegts_word32(tsb+3*188) & mask) == val) {
+      r   += 4*188;
+      len -= 4*188;
+      tsb += 4*188;
+    } else if ((mpegts_word32(tsb) & mask) == val) {
+      r   += 188;
+      len -= 188;
+      tsb += 188;
+    } else {
+      break;
+    }
+  }
+
+  return r;
+}