]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Add ability to parse whole frames (without the reassembly stuff)
authorAndreas Öman <andreas@lonelycoder.com>
Wed, 6 Feb 2008 21:50:58 +0000 (21:50 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Wed, 6 Feb 2008 21:50:58 +0000 (21:50 +0000)
parsers.c
parsers.h

index 399f035ad8e8c79d0bcfab57d57cd77a97c8dabf..345425b7f5fc71876bc445fd26e319a0321b695c 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -465,6 +465,62 @@ const static unsigned int mpeg2video_framedurations[16] = {
   1500,
 };
 
+/**
+ * Parse mpeg2video picture start
+ */
+static int
+parse_mpeg2video_pic_start(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt,
+                          bitstream_t *bs)
+{
+  int v, pct;
+
+  if(bs->len < 6 * 8)
+    return 1;
+
+  skip_bits(bs, 10); /* temporal reference */
+
+  pct = read_bits(bs, 3);
+  if(pct < PKT_I_FRAME || pct > PKT_B_FRAME)
+    return 1; /* Illegal picture_coding_type */
+
+  /* If this is the first I-frame seen, set dts_start as a reference
+     offset */
+  if(pct == PKT_I_FRAME && t->tht_dts_start == AV_NOPTS_VALUE)
+    t->tht_dts_start = st->st_curdts;
+
+  v = read_bits(bs, 16); /* vbv_delay */
+  if(v == 0xffff)
+    st->st_vbv_delay = -1;
+  else
+    st->st_vbv_delay = av_rescale_q(v, st->st_tb, AV_TIME_BASE_Q);
+  return 0;
+}
+
+/**
+ * Parse mpeg2video sequence start
+ */
+static int
+parse_mpeg2video_seq_start(th_transport_t *t, th_stream_t *st,
+                          bitstream_t *bs)
+{
+  int v;
+
+  if(bs->len < 11 * 8)
+    return 1;
+  
+  skip_bits(bs, 12);
+  skip_bits(bs, 12);
+  skip_bits(bs, 4);
+  st->st_frame_duration = mpeg2video_framedurations[read_bits(bs, 4)];
+  v = read_bits(bs, 18) * 400;
+  skip_bits(bs, 1);
+  
+  v = read_bits(bs, 10) * 16 * 1024 / 8;
+  st->st_vbv_size = v;
+  return 0;
+}
+
+
 /**
  * MPEG2VIDEO specific reassembly
  *
@@ -481,7 +537,7 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
 {
   uint8_t *buf = st->st_buffer + sc_offset;
   bitstream_t bs;
-  int v, pct;
+  th_pkt_t pkt0;  /* Fake temporary packet */
 
   init_bits(&bs, buf + 4, (len - 4) * 8);
 
@@ -497,31 +553,14 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
     if(st->st_frame_duration == 0 || st->st_curdts == AV_NOPTS_VALUE)
       return 1;
 
-    if(len < 6)
+    if(parse_mpeg2video_pic_start(t, st, &pkt0, &bs))
       return 1;
 
-    skip_bits(&bs, 10); /* temporal reference */
-
-    pct = read_bits(&bs, 3);
-    if(pct < PKT_I_FRAME || pct > PKT_B_FRAME)
-      return 1; /* Illegal picture_coding_type */
-
-   /* If this is the first I-frame seen, set dts_start as a reference
-       offset */
-    if(pct == PKT_I_FRAME && t->tht_dts_start == AV_NOPTS_VALUE)
-      t->tht_dts_start = st->st_curdts;
-
-    v = read_bits(&bs, 16); /* vbv_delay */
-    if(v == 0xffff)
-      st->st_vbv_delay = -1;
-    else
-      st->st_vbv_delay = av_rescale_q(v, st->st_tb, AV_TIME_BASE_Q);
     if(st->st_curpkt != NULL)
       pkt_deref(st->st_curpkt);
 
     st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
-    st->st_curpkt->pkt_frametype = pct;
+    st->st_curpkt->pkt_frametype = pkt0.pkt_frametype;
     st->st_curpkt->pkt_duration = st->st_frame_duration;
     st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
 
@@ -529,18 +568,9 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
 
   case 0x000001b3:
     /* Sequence start code */
-    if(len < 11)
+    if(parse_mpeg2video_seq_start(t, st, &bs))
       return 1;
 
-    skip_bits(&bs, 12);
-    skip_bits(&bs, 12);
-    skip_bits(&bs, 4);
-    st->st_frame_duration = mpeg2video_framedurations[read_bits(&bs, 4)];
-    v = read_bits(&bs, 18) * 400;
-    skip_bits(&bs, 1);
-
-    v = read_bits(&bs, 10) * 16 * 1024 / 8;
-    st->st_vbv_size = v;
     break;
 
   case 0x000001b5:
@@ -747,8 +777,6 @@ parser_compute_duration(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
   d = next->pkt_dts - pkt->pkt_dts;
   TAILQ_REMOVE(&st->st_durationq, pkt, pkt_queue_link);
   if(d < 10) {
-    printf("%s: duration is %lld, pkt dropped\n", 
-          htstvstreamtype2txt(st->st_type), d);
     pkt_deref(pkt);
     return;
   }
@@ -817,6 +845,8 @@ parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
 #endif
   pkt->pkt_stream = st;
   
+  avgstat_add(&st->st_rate, pkt->pkt_payloadlen, dispatch_clock);
+
   /* Alert all muxers tied to us that a new packet has arrived */
   
   LIST_FOREACH(tm, &t->tht_muxers, tm_transport_link)
@@ -827,3 +857,64 @@ parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
 
   pkt_deref(pkt);
 }
+
+/**
+ * Receive whole frames
+ *
+ * Analyze them as much as we need to and patch up PTS and duration
+ * if needed
+ */
+void
+parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
+{
+  uint8_t *buf = pkt->pkt_payload;
+  uint32_t sc = 0xffffffff;
+  int i, err = 0, rem;
+  bitstream_t bs;
+
+  assert(pkt->pkt_dts != AV_NOPTS_VALUE); /* We require DTS to be set */
+  pkt->pkt_duration = 0;
+
+  /* Per stream type analysis */
+  
+  switch(st->st_type) {
+  case HTSTV_MPEG2VIDEO:
+    for(i = 0; i < pkt->pkt_payloadlen && err == 0; i++) {
+      sc = (sc << 8) | buf[i];
+
+      if((sc & 0xffffff00) != 0x00000100)
+       continue;
+
+      if(sc >= 0x101 && sc <= 0x1af)
+       break; /* slices, dont scan further */
+
+      rem = pkt->pkt_payloadlen - i - 1;
+      init_bits(&bs, buf + i + 1, rem);
+
+      switch(sc) {
+      case 0x00000100: /* Picture start code */
+       err = parse_mpeg2video_pic_start(t, st, pkt, &bs);
+       break;
+
+      case 0x000001b3: /* Sequence start code */
+       if(t->tht_dts_start == AV_NOPTS_VALUE)
+         t->tht_dts_start = pkt->pkt_dts;
+       err = parse_mpeg2video_seq_start(t, st, &bs);
+       break;
+      }
+    }
+    break;
+
+  default:
+    pkt->pkt_pts = pkt->pkt_dts;
+    break;
+  }
+
+  if(err) {
+    pkt_deref(pkt);
+    return;
+  }
+    
+
+  parse_compute_pts(t, st, pkt);
+}
index d9a7379270bb4252ed5963b7bb9118db1fbd0a7d..2f6c9488dba36e30c008bb8ba27a904762054661 100644 (file)
--- a/parsers.h
+++ b/parsers.h
@@ -27,4 +27,6 @@ void parser_compute_duration(th_transport_t *t, th_stream_t *st,
 
 void parse_compute_pts(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
 
+void parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
+
 #endif /* PARSERS_H */