]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Splice "global data" (sequence headers for MPEG2 and SPS/PPS for h264) into
authorAndreas Öman <andreas@lonelycoder.com>
Mon, 14 Jun 2010 12:32:57 +0000 (12:32 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Mon, 14 Jun 2010 12:32:57 +0000 (12:32 +0000)
packet buffers of its own.

Make all subscribers merge it back for now. We will need this for correctly
writing global headers in MKV files.

Ticket #61

src/dvr/dvr_rec.c
src/htsp.c
src/packet.c
src/packet.h
src/parsers.c
src/rtsp.c
src/transports.c
src/tvhead.h

index c20e9baff3ad38a0a4ddb0790002cce7b5476bf3..3c5d7497f3bb215e84424bb8bb6961c9b71c73c7 100644 (file)
@@ -595,6 +595,8 @@ dvr_thread_new_pkt(dvr_entry_t *de, th_pkt_t *pkt)
   char txt[100];
   int64_t pts, dts;
 
+  pkt = pkt_merge_global(pkt);
+
   LIST_FOREACH(drs, &de->de_streams, drs_link)
     if(drs->drs_source_index == pkt->pkt_componentindex)
       break;
index a3bf5958eda4d45764eda9d3d8e7568aa550a8fa..65cacf056311deaa79085ff553fcd44e06aebc17 100644 (file)
@@ -1413,6 +1413,8 @@ htsp_stream_deliver(htsp_subscription_t *hs, th_pkt_t *pkt)
   htsmsg_add_s64(m, "pts",      pts);
   htsmsg_add_u32(m, "duration", dur);
   
+  pkt = pkt_merge_global(pkt);
+
   /**
    * Since we will serialize directly we use 'binptr' which is a binary
    * object that just points to data, thus avoiding a copy.
index 1d792d16a9973b66adb85bc7f588d85175575da0..b9740a9d1f5836b59d9dbd70d595d58aeeb23565 100644 (file)
@@ -29,6 +29,7 @@ static void
 pkt_destroy(th_pkt_t *pkt)
 {
   free(pkt->pkt_payload);
+  free(pkt->pkt_globaldata);
   free(pkt);
 }
 
@@ -100,3 +101,34 @@ pktref_clear_queue(struct th_pktref_queue *q)
     free(pr);
   }
 }
+
+
+/**
+ *
+ */
+th_pkt_t *
+pkt_merge_global(th_pkt_t *pkt)
+{
+  th_pkt_t *n;
+
+  if(pkt->pkt_globaldata == NULL)
+    return pkt;
+
+  n = malloc(sizeof(th_pkt_t));
+  *n = *pkt;
+
+  n->pkt_refcount = 1;
+  n->pkt_globaldata = NULL;
+  n->pkt_globaldata_len = 0;
+  
+  n->pkt_payloadlen = pkt->pkt_globaldata_len + pkt->pkt_payloadlen;
+
+  n->pkt_payload = malloc(n->pkt_payloadlen + FF_INPUT_BUFFER_PADDING_SIZE);
+  memcpy(n->pkt_payload, pkt->pkt_globaldata, pkt->pkt_globaldata_len);
+  memcpy(n->pkt_payload + pkt->pkt_globaldata_len, pkt->pkt_payload,
+        pkt->pkt_payloadlen);
+
+  pkt_ref_dec(pkt);
+  
+  return n;
+}
index e53e3827697dbcef83c5362d1701f6d11244092b..e2cffeab6ba16fc6b4dfa9fa2671a2db0c206e16 100644 (file)
@@ -41,6 +41,9 @@ typedef struct th_pkt {
   uint8_t *pkt_payload;
   int pkt_payloadlen;
 
+  uint8_t *pkt_globaldata;
+  int pkt_globaldata_len;
+
 } th_pkt_t;
 
 
@@ -66,4 +69,6 @@ void pktref_clear_queue(struct th_pktref_queue *q);
 
 th_pkt_t *pkt_alloc(void *data, size_t datalen, int64_t pts, int64_t dts);
 
+th_pkt_t *pkt_merge_global(th_pkt_t *pkt);
+
 #endif /* PACKET_H_ */
index c9dfadf3971572819fff8339cd26a07b38fb364d..59f3915fc51ec95ae1eb404fd49f07cad6f4af8f 100644 (file)
@@ -293,7 +293,7 @@ parse_video(th_transport_t *t, th_stream_t *st, const uint8_t *data, int len,
     if((sc & 0xffffff00) != 0x00000100)
       continue;
 
-    r = st->st_buffer_ptr - 4;
+    r = st->st_buffer_ptr - st->st_startcode_offset - 4;
 
     if(r > 0 && st->st_startcode != 0) {
       r = vp(t, st, r, sc, st->st_startcode_offset);
@@ -301,17 +301,29 @@ parse_video(th_transport_t *t, th_stream_t *st, const uint8_t *data, int len,
       r = 1;
     }
 
-    if(r) {
-      /* Reset packet parser upon length error or if parser
-        tells us so */
-      st->st_buffer_ptr = 0;
+    if(r == 2) {
+      // Drop packet
+      st->st_buffer_ptr = st->st_startcode_offset;
+
       st->st_buffer[st->st_buffer_ptr++] = sc >> 24;
       st->st_buffer[st->st_buffer_ptr++] = sc >> 16;
       st->st_buffer[st->st_buffer_ptr++] = sc >> 8;
-      st->st_buffer[st->st_buffer_ptr++] = sc >> 0;
+      st->st_buffer[st->st_buffer_ptr++] = sc;
+      st->st_startcode = sc;
+
+    } else {
+      if(r == 1) {
+       /* Reset packet parser upon length error or if parser
+          tells us so */
+       st->st_buffer_ptr = 0;
+       st->st_buffer[st->st_buffer_ptr++] = sc >> 24;
+       st->st_buffer[st->st_buffer_ptr++] = sc >> 16;
+       st->st_buffer[st->st_buffer_ptr++] = sc >> 8;
+       st->st_buffer[st->st_buffer_ptr++] = sc;
+      }
+      st->st_startcode = sc;
+      st->st_startcode_offset = st->st_buffer_ptr - 4;
     }
-    st->st_startcode = sc;
-    st->st_startcode_offset = st->st_buffer_ptr - 4;
   }
   st->st_startcond = sc;  
 
@@ -676,6 +688,23 @@ parse_mpeg2video_seq_start(th_transport_t *t, th_stream_t *st,
 }
 
 
+/**
+ *
+ */
+static void
+parser_global_data_move(th_stream_t *st, const uint8_t *data, size_t len)
+{
+  st->st_global_data = realloc(st->st_global_data,
+                              st->st_global_data_len + len + 
+                              FF_INPUT_BUFFER_PADDING_SIZE);
+  
+  memcpy(st->st_global_data + st->st_global_data_len, data, len);
+  st->st_global_data_len += len;
+
+  st->st_buffer_ptr -= len;
+}
+
+
 /**
  * MPEG2VIDEO specific reassembly
  *
@@ -724,41 +753,48 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
     /* Sequence start code */
     if(parse_mpeg2video_seq_start(t, st, &bs))
       return 1;
-
-    break;
+    parser_global_data_move(st, buf, len);
+    return 2;
 
   case 0x000001b5:
     if(len < 5)
       return 1;
     switch(buf[4] >> 4) {
     case 0x1:
-      /* sequence extension */
-      //      printf("Sequence extension, len = %d\n", len);
-      if(len < 10)
-       return 1;
-      //      printf("Profile = %d\n", buf[4] & 0x7);
-      //      printf("  Level = %d\n", buf[5] >> 4);
-      break;
+      // Sequence Extension
+      parser_global_data_move(st, buf, len);
+      return 2;
+    case 0x2:
+      // Sequence Display Extension
+      parser_global_data_move(st, buf, len);
+      return 2;
     }
     break;
 
-
   case 0x00000101 ... 0x000001af:
     /* Slices */
 
     if(next_startcode == 0x100 || next_startcode > 0x1af) {
       /* Last picture slice (because next not a slice) */
-
-      if(st->st_curpkt == NULL) {
+      th_pkt_t *pkt = st->st_curpkt;
+      if(pkt == NULL) {
        /* no packet, may've been discarded by sanity checks here */
        return 1; 
       }
 
-      st->st_curpkt->pkt_payload = st->st_buffer;
-      st->st_curpkt->pkt_payloadlen = st->st_buffer_ptr - 4;
-      st->st_curpkt->pkt_duration = st->st_frame_duration;
+      if(st->st_global_data) {
+       pkt->pkt_globaldata = st->st_global_data;
+       pkt->pkt_globaldata_len = st->st_global_data_len;
+       
+       st->st_global_data = NULL;
+       st->st_global_data_len = 0;
+      }
 
-      parse_compute_pts(t, st, st->st_curpkt);
+      pkt->pkt_payload = st->st_buffer;
+      pkt->pkt_payloadlen = st->st_buffer_ptr - 4;
+      pkt->pkt_duration = st->st_frame_duration;
+
+      parse_compute_pts(t, st, pkt);
       st->st_curpkt = NULL;
 
       st->st_buffer = malloc(st->st_buffer_size);
@@ -772,6 +808,15 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
     }
     break;
 
+  case 0x000001b8:
+    // GOP header
+    parser_global_data_move(st, buf, len);
+    return 2;
+
+  case 0x000001b2:
+    // User data
+    break;
+
   default:
     break;
   }
@@ -790,20 +835,12 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
   uint8_t *buf = st->st_buffer + sc_offset;
   uint32_t sc = st->st_startcode;
   int64_t d;
-  int l2, pkttype, l;
+  int l2, pkttype;
   bitstream_t bs;
-
-  if(sc == 0x10c) {
-    /* RBSP padding, we don't want this */
-    
-    l = len - sc_offset;
-    memcpy(buf, buf + l, 4); /* Move down new start code */
-    st->st_buffer_ptr -= l;  /* Drop buffer */
-  }
+  int ret = 0;
 
   if(sc >= 0x000001e0 && sc <= 0x000001ef) {
     /* System start codes for video */
-
     if(len >= 9)
       parse_pes_header(t, st, buf + 6, len - 6);
 
@@ -819,68 +856,84 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
   
   bs.data = NULL;
 
-  switch(sc & 0x1f) {
+  if(sc == 0x10c) {
+    // Padding
 
-  case 7:
-    h264_nal_deescape(&bs, buf + 3, len - 3);
-    if(h264_decode_seq_parameter_set(st, &bs)) {
-      free(bs.data);
-      return 1;
-    }
-    break;
+    st->st_buffer_ptr -= len;
+    ret = 2;
 
-  case 8:
-    h264_nal_deescape(&bs, buf + 3, len - 3);
-    if(h264_decode_pic_parameter_set(st, &bs)) {
-      free(bs.data);
-      return 1;
-    }
-    break;
+  } else {
 
+    switch(sc & 0x1f) {
 
-  case 5: /* IDR+SLICE */
-  case 1:
-    if(st->st_curpkt != NULL || st->st_frame_duration == 0 ||
-       st->st_curdts == AV_NOPTS_VALUE)
+    case 7:
+      h264_nal_deescape(&bs, buf + 3, len - 3);
+      h264_decode_seq_parameter_set(st, &bs);
+      parser_global_data_move(st, buf, len);
+      ret = 2;
       break;
 
-    if(t->tht_dts_start == AV_NOPTS_VALUE)
-      t->tht_dts_start = st->st_curdts;
+    case 8:
 
-    l2 = len - 3 > 64 ? 64 : len - 3;
-    h264_nal_deescape(&bs, buf + 3, l2); /* we just the first stuff */
-    if(h264_decode_slice_header(st, &bs, &pkttype)) {
-      free(bs.data);
-      return 1;
-    }
+      h264_nal_deescape(&bs, buf + 3, len - 3);
+      h264_decode_pic_parameter_set(st, &bs);
+      parser_global_data_move(st, buf, len);
+      ret = 2;
+      break;
 
-    st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
-    st->st_curpkt->pkt_frametype = pkttype;
-    st->st_curpkt->pkt_duration = st->st_frame_duration;
-    st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
-    break;
+    case 5: /* IDR+SLICE */
+    case 1:
+      if(st->st_curpkt != NULL || st->st_frame_duration == 0 ||
+        st->st_curdts == AV_NOPTS_VALUE)
+       break;
 
-  default:
-    break;
-  }
+      if(t->tht_dts_start == AV_NOPTS_VALUE)
+       t->tht_dts_start = st->st_curdts;
+
+      l2 = len - 3 > 64 ? 64 : len - 3;
+      h264_nal_deescape(&bs, buf + 3, l2); /* we just want the first stuff */
+      if(h264_decode_slice_header(st, &bs, &pkttype)) {
+       free(bs.data);
+       return 1;
+      }
+
+      st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
+      st->st_curpkt->pkt_frametype = pkttype;
+      st->st_curpkt->pkt_duration = st->st_frame_duration;
+      st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
+      break;
 
+    default:
+      break;
+    }
+  }
   free(bs.data);
 
   if(next_startcode >= 0x000001e0 && next_startcode <= 0x000001ef) {
     /* Complete frame */
-    
-    if(st->st_curpkt == NULL)
-      return 1;
 
-    st->st_curpkt->pkt_payload = st->st_buffer;
-    st->st_curpkt->pkt_payloadlen = st->st_buffer_ptr;
-    parser_deliver(t, st, st->st_curpkt, 1);
+    th_pkt_t *pkt = st->st_curpkt;
     
-    st->st_curpkt = NULL;
-    st->st_buffer = malloc(st->st_buffer_size);
+    if(pkt != NULL) {
+      
+      if(st->st_global_data) {
+       pkt->pkt_globaldata = st->st_global_data;
+       pkt->pkt_globaldata_len = st->st_global_data_len;
+       st->st_global_data = NULL;
+       st->st_global_data_len = 0;
+      }
+    
+      pkt->pkt_payload = st->st_buffer;
+      pkt->pkt_payloadlen = st->st_buffer_ptr - 4;
+      parser_deliver(t, st, pkt, 1);
+      
+      st->st_curpkt = NULL;
+      st->st_buffer = malloc(st->st_buffer_size);
+    }
     return 1;
   }
-  return 0;
+
+  return ret;
 }
 
 /**
index 4f9be83c96fe58efa393d97c6037594438519b80..54876d679cffb544c2a7197909e665acae836680 100644 (file)
@@ -391,6 +391,8 @@ rtsp_streaming_send(rtsp_t *rtsp, th_pkt_t *pkt)
 {
   rtsp_stream_t *rs;
 
+  pkt = pkt_merge_global(pkt);
+
   LIST_FOREACH(rs, &rtsp->rtsp_streams, rs_link)
     if(rs->rs_index == pkt->pkt_componentindex)
       break;
index c69421f557386692857dd8ff114275386dd70177..9d574ecbb66aab55e7be9cc7801beb796f3fdc98 100644 (file)
@@ -154,6 +154,10 @@ stream_clean(th_stream_t *st)
     st->st_curpkt = NULL;
   }
 
+  free(st->st_global_data);
+  st->st_global_data = NULL;
+  st->st_global_data_len = 0;
+
   /* Clear PTS queue */
 
   pktref_clear_queue(&st->st_ptsq);
index f51478c44ef47aca13f08dfba9732b30cbeb71c9..6baad71651ef8b68cb2aaffe33191325c1c217a1 100644 (file)
@@ -415,6 +415,8 @@ typedef struct th_stream {
   int st_buffer2_ptr;
   int st_buffer2_size;
 
+  uint8_t *st_global_data;
+  int st_global_data_len;
 
   struct th_pkt *st_curpkt;
   int64_t st_curpts;
@@ -426,7 +428,7 @@ typedef struct th_stream {
   int st_height;
 
   int st_meta_change;
-
+  
   /* DTS generator */
 
   int64_t st_dts_epoch;  /* upper bits (auto generated) */