]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
parsers: improve AAC/LATM parser
authorJaroslav Kysela <perex@perex.cz>
Sun, 8 Feb 2015 17:19:25 +0000 (18:19 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 11 Feb 2015 12:41:24 +0000 (13:41 +0100)
src/parsers/bitstream.c
src/parsers/bitstream.h
src/parsers/parser_latm.c
src/parsers/parsers.c
src/plumbing/globalheaders.c
src/plumbing/transcoding.c

index 73f7e1890fda88c82311de5028f551eb3ef671c4..ffb7eef8227354dc2ec9c4603da8049c5238ae0a 100644 (file)
@@ -40,23 +40,10 @@ init_wbits(bitstream_t *bs, uint8_t *data, int bits)
   bs->len = bits;
 }
 
-void
-skip_bits(bitstream_t *bs, int num)
-{
-  bs->offset += num;
-}
-
-int
-bs_eof(const bitstream_t *bs)
-{
-  return bs->offset >= bs->len;
-}
-
-
 unsigned int
 read_bits(bitstream_t *bs, int num)
 {
-  int r = 0;
+  unsigned int r = 0;
 
   while(num > 0) {
     if(bs->offset >= bs->len)
@@ -73,9 +60,22 @@ read_bits(bitstream_t *bs, int num)
 }
 
 unsigned int
-read_bits1(bitstream_t *bs)
+show_bits(bitstream_t *bs, int num)
 {
-  return read_bits(bs, 1);
+  unsigned int r = 0, offset = bs->offset;
+
+  while(num > 0) {
+    if(offset >= bs->len)
+      return 0;
+
+    num--;
+
+    if(bs->rdata[offset / 8] & (1 << (7 - (offset & 7))))
+      r |= 1 << num;
+
+    offset++;
+  }
+  return r;
 }
 
 unsigned int
@@ -106,13 +106,6 @@ read_golomb_se(bitstream_t *bs)
 }
 
 
-unsigned int
-remaining_bits(bitstream_t *bs)
-{
-  return bs->len - bs->offset;
-}
-
-
 void
 put_bits(bitstream_t *bs, int val, int num)
 {
index 8718e80bb3872cca48613cf36d87a4eaa688138a..f43f036ff90e2796200d70a15237d18f8eac4568 100644 (file)
@@ -26,7 +26,8 @@ typedef struct bitstream {
   int len;
 } bitstream_t;
 
-void skip_bits(bitstream_t *bs, int num);
+static inline void skip_bits(bitstream_t *bs, int num)
+  { bs->offset += num; }
 
 void init_rbits(bitstream_t *bs, const uint8_t *data, int bits);
 
@@ -34,16 +35,21 @@ void init_wbits(bitstream_t *bs, uint8_t *data, int bits);
 
 unsigned int read_bits(bitstream_t *gb, int num);
 
-unsigned int read_bits1(bitstream_t *gb);
+unsigned int show_bits(bitstream_t *gb, int num);
+
+static inline unsigned int read_bits1(bitstream_t *gb)
+  { return read_bits(gb, 1); }
 
 unsigned int read_golomb_ue(bitstream_t *gb);
 
 signed int read_golomb_se(bitstream_t *gb);
 
-unsigned int remaining_bits(bitstream_t *gb);
+static inline unsigned int remaining_bits(bitstream_t *gb)
+  { return gb->len - gb->offset; }
 
 void put_bits(bitstream_t *bs, int val, int num);
 
-int bs_eof(const bitstream_t *bs);
+static inline int bs_eof(const bitstream_t *bs)
+  { return bs->offset >= bs->len; }
 
 #endif /* BITSTREAM_H_ */
index 0dc2105bdd70cb08419f1d9066a892d983621b89..b54170ff2f8c6eb03887494d2a9ac3da7645f744 100644 (file)
@@ -40,6 +40,7 @@ typedef struct latm_private {
 
   int configured;
   int audio_mux_version_A;
+  int aot;
   int frame_length_type;
 
   int sample_rate_index;
@@ -55,74 +56,110 @@ latm_get_value(bitstream_t *bs)
     return read_bits(bs, read_bits(bs, 2) * 8);
 }
 
+#define AOT_AAC_MAIN  1
+#define AOT_AAC_LC    2
+#define AOT_AAC_SSR   3
+#define AOT_AAC_LTP   4
+#define AOT_SBR       5
+#define AOT_PS       26
+#define AOT_ESCAPE   28
 
-static void
+static inline int adts_aot(int aot)
+{
+  switch (aot) {
+  case AOT_AAC_MAIN: return 0;
+  case AOT_AAC_LC  : return 1;
+  case AOT_AAC_SSR : return 2;
+  default:           return 3; /* reserved or LTP */
+  }
+}
+
+static inline int read_aot(bitstream_t *bs)
+{
+  int aot = read_bits(bs, 5);
+  if (aot == AOT_ESCAPE)
+    aot = read_bits(bs, 6);
+  return aot;
+}
+
+static inline int read_sr(bitstream_t *bs, int *sri)
+{
+  *sri = read_bits(bs, 4);
+  if (*sri == 0x0f)
+    return read_bits(bs, 24);
+  else
+    return sri_to_rate(*sri);
+}
+
+static int
 read_audio_specific_config(elementary_stream_t *st, latm_private_t *latm,
                           bitstream_t *bs)
 {
   int aot, sr;
 
-  aot = read_bits(bs, 5);
-
-  latm->sample_rate_index = read_bits(bs, 4);
-
-  if(latm->sample_rate_index == 0xf)
-    sr = read_bits(bs, 24);
-  else
-    sr = sri_to_rate(latm->sample_rate_index);
+  if ((bs->offset % 8) != 0)
+    return -1;
 
-  if(sr == 0)
-    return;
+  aot = read_aot(bs);
+  sr  = read_sr(bs, &latm->sample_rate_index);
+  latm->channel_config  = read_bits(bs, 4);
 
   st->es_frame_duration = 1024 * 90000 / sr;
 
-  latm->channel_config = read_bits(bs, 4);
-
-  if (aot == 5) { // AOT_SBR
-    if (read_bits(bs, 4) == 0xf) {  // extensionSamplingFrequencyIndex
-       skip_bits(bs, 24);
-    }
-    aot = read_bits(bs, 5);    // this is the main object type (i.e. non-extended)
+  if (aot == AOT_SBR ||
+      (aot == AOT_PS && !(show_bits(bs, 3) & 3 && !(show_bits(bs, 9) & 0x3f)))) {
+    sr  = read_sr(bs, &latm->sample_rate_index);
+    aot = read_aot(bs);                // this is the main object type (i.e. non-extended)
   }
 
-  if(aot != 2)
-    return;
+  if (sr == 0 || latm->channel_config == 0)
+    return -1;
+  if (aot != AOT_AAC_MAIN && aot != AOT_AAC_LC &&
+      aot != AOT_AAC_SSR  && aot != AOT_AAC_LTP)
+    return -1;
+  latm->aot = aot;
 
-  skip_bits(bs, 1); //framelen_flag
-  if(read_bits1(bs))  // depends_on_coder
+  if (read_bits1(bs))   // framelen_flag
+    return -1;
+  if (read_bits1(bs))    // depends_on_coder
     skip_bits(bs, 14);
 
-  if(read_bits(bs, 1))  // ext_flag
+  if (read_bits1(bs))    // ext_flag
      skip_bits(bs, 1);  // ext3_flag
+  return 0;
 }
 
 
-static void
+static int
 read_stream_mux_config(elementary_stream_t *st, latm_private_t *latm, bitstream_t *bs)
 {
-  int audio_mux_version = read_bits(bs, 1);
+  int audio_mux_version = read_bits1(bs);
   latm->audio_mux_version_A = 0;
-  if(audio_mux_version)                       // audioMuxVersion
-    latm->audio_mux_version_A = read_bits(bs, 1);
+  if(audio_mux_version)                     // audioMuxVersion
+    latm->audio_mux_version_A = read_bits1(bs);
   
   if(latm->audio_mux_version_A)
-    return;
+    return 0;
 
   if(audio_mux_version)
-    latm_get_value(bs);                  // taraFullness
+    latm_get_value(bs);                     // taraFullness
 
   skip_bits(bs, 1);                         // allStreamSameTimeFraming = 1
   skip_bits(bs, 6);                         // numSubFrames = 0
-  skip_bits(bs, 4);                         // numPrograms = 0
 
-  // for each program (which there is only on in DVB)
-  skip_bits(bs, 3);                         // numLayer = 0
+  if (read_bits(bs, 4))                     // numPrograms = 0
+    return -1;
+
+  // for each program (only one in DVB)
+  if (read_bits(bs, 3))                     // numLayer = 0
+    return -1;
     
-  // for each layer (which there is only on in DVB)
-  if(!audio_mux_version)
-    read_audio_specific_config(st, latm, bs);
-  else {
-    return;
+  // for each layer (which there is only one in DVB)
+  if(!audio_mux_version) {
+    if (read_audio_specific_config(st, latm, bs) < 0)
+      return -1;
+  } else {
+    return -1;
 #if 0 // see bellow (look for dead code)
     uint32_t ascLen = latm_get_value(bs);
     abort(); // ascLen -= read_audio_specific_config(filter, gb);
@@ -150,24 +187,25 @@ read_stream_mux_config(elementary_stream_t *st, latm_private_t *latm, bitstream_
     break;
   }
 
-  if(read_bits(bs, 1)) {                   // other data?
+  if(read_bits1(bs)) {                // other data?
 #if 0 // coverity - dead code - see above
     if(audio_mux_version)
-      latm_get_value(bs);              // other_data_bits
+      latm_get_value(bs);             // other_data_bits
     else
 #endif
     {
       int esc;
       do {
-       esc = read_bits(bs, 1);
+       esc = read_bits1(bs);
        skip_bits(bs, 8);
       } while (esc);
     }
   }
 
-  if(read_bits(bs, 1))                   // crc present?
-    skip_bits(bs, 8);                     // config_crc
+  if(read_bits1(bs))                  // crc present?
+    skip_bits(bs, 8);                 // config_crc
   latm->configured = 1;
+  return 0;
 }
 
 /**
@@ -188,7 +226,8 @@ parse_latm_audio_mux_element(service_t *t, elementary_stream_t *st,
     latm = st->es_priv = calloc(1, sizeof(latm_private_t));
 
   if(!read_bits1(&bs))
-    read_stream_mux_config(st, latm, &bs);
+    if (read_stream_mux_config(st, latm, &bs) < 0)
+      return NULL;
 
   if(!latm->configured)
     return NULL;
@@ -202,8 +241,7 @@ parse_latm_audio_mux_element(service_t *t, elementary_stream_t *st,
     slot_len += tmp;
   } while (tmp == 255);
 
-
-  if(slot_len * 8 > remaining_bits(&bs))
+  if (slot_len * 8 > remaining_bits(&bs))
     return NULL;
 
   if(st->es_curdts == PTS_UNSET)
@@ -214,16 +252,16 @@ parse_latm_audio_mux_element(service_t *t, elementary_stream_t *st,
   pkt->pkt_commercial = t->s_tt_commercial_advice;
   pkt->pkt_duration = st->es_frame_duration;
   pkt->pkt_sri = latm->sample_rate_index;
-  pkt->pkt_channels = latm->channel_config;
+  pkt->pkt_channels = latm->channel_config == 7 ? 8 : latm->channel_config;
 
   /* 7 bytes of ADTS header */
-  init_wbits(&out, pktbuf_ptr(pkt->pkt_payload), 56);
+  init_wbits(&out, pktbuf_ptr(pkt->pkt_payload), 7 * 8);
 
   put_bits(&out, 0xfff, 12); // Sync marker
-  put_bits(&out, 1, 1);      // ID 0 = MPEG 4, 1 = MPEG 2
+  put_bits(&out, 0, 1);      // ID 0 = MPEG 4, 1 = MPEG 2
   put_bits(&out, 0, 2);      // Layer
   put_bits(&out, 1, 1);      // Protection absent
-  put_bits(&out, 2, 2);      // AOT, 2 = AAC LC (for MPEG 2 bit)
+  put_bits(&out, adts_aot(latm->aot), 2);
   put_bits(&out, latm->sample_rate_index, 4);
   put_bits(&out, 1, 1);      // Private bit
   put_bits(&out, latm->channel_config, 3);
@@ -233,7 +271,7 @@ parse_latm_audio_mux_element(service_t *t, elementary_stream_t *st,
   put_bits(&out, 1, 1);      // Copyright identification bit
   put_bits(&out, 1, 1);      // Copyright identification start
   put_bits(&out, slot_len + 7, 13);
-  put_bits(&out, 0, 11);     // Buffer fullness
+  put_bits(&out, 0x7ff, 11); // Buffer fullness
   put_bits(&out, 0, 2);      // RDB in frame
 
   assert(remaining_bits(&out) == 0);
index a1d630c5a511da689b7629b2520ba52549f70e87..bb1b1af8aad2bb31fcc801784236937e021924a8 100644 (file)
@@ -227,35 +227,48 @@ static void
 parse_aac(service_t *t, elementary_stream_t *st, const uint8_t *data,
           int len, int start)
 {
-  int l, muxlen, p;
+  int l, muxlen, p, hdr = 0;
   th_pkt_t *pkt;
-
-  if(start) {
-    /* Payload unit start */
-    st->es_parser_state = 1;
-    st->es_parser_ptr = 0;
-    sbuf_reset(&st->es_buf, 4000);
+  int64_t olddts = PTS_UNSET, oldpts = PTS_UNSET;
+  int64_t newdts = PTS_UNSET, newpts = PTS_UNSET;
+
+  if(st->es_parser_state == 0) {
+    if (start) {
+      /* Payload unit start */
+      st->es_parser_state = 1;
+      st->es_parser_ptr = 0;
+      sbuf_reset(&st->es_buf, 4000);
+    } else {
+      return;
+    }
   }
 
-  if(st->es_parser_state == 0)
-    return;
-
-  sbuf_append(&st->es_buf, data, len);
-
-  if(st->es_parser_ptr == 0) {
+  if(start) {
     int hlen;
 
-    if(st->es_buf.sb_ptr < 9)
+    if(len < 9)
       return;
 
-    hlen = parse_pes_header(t, st,
-                            st->es_buf.sb_data + 6, st->es_buf.sb_ptr - 6);
+    olddts = st->es_curdts;
+    oldpts = st->es_curpts;
+    hlen = parse_pes_header(t, st, data + 6, len - 6);
+    if (hlen >= 0 && st->es_buf.sb_ptr) {
+      newdts = st->es_curdts;
+      newpts = st->es_curpts;
+      st->es_curdts = olddts;
+      st->es_curpts = oldpts;
+    }
+
     if(hlen < 0)
       return;
-    st->es_parser_ptr += 6 + hlen;
+
+    data += 6 + hlen;
+    len  -= 6 + hlen;
   }
 
-  p = st->es_parser_ptr;
+  sbuf_append(&st->es_buf, data, len);
+
+  p = 0;
 
   while((l = st->es_buf.sb_ptr - p) > 3) {
     const uint8_t *d = st->es_buf.sb_data + p;
@@ -274,12 +287,17 @@ parse_aac(service_t *t, elementary_stream_t *st, const uint8_t *data,
         st->es_buf.sb_err = 0;
       }
 
+      if (hdr && newdts != PTS_UNSET) {
+        st->es_curdts = newdts;
+        st->es_curpts = newpts;
+      }
       p += muxlen + 3;
     /* ADTS */
-    } else if(d[0] == 0xff && (d[1] & 0xf0) == 0xf0) {
+    } else if(p == 0 && d[0] == 0xff && (d[1] & 0xf0) == 0xf0) {
 
       if (l < 7)
         break;
+
       muxlen = ((uint16_t)(d[3] & 0x03) << 11) | ((uint16_t)d[4] << 3) | (d[5] >> 5);
       if (l < muxlen)
         break;
@@ -288,6 +306,10 @@ parse_aac(service_t *t, elementary_stream_t *st, const uint8_t *data,
       sbuf_append(&st->es_buf_a, d, muxlen);
       parse_mp4a_data(t, st, 1);
 
+      if (hdr && newdts != PTS_UNSET) {
+        st->es_curdts = newdts;
+        st->es_curpts = newpts;
+      }
       p += muxlen;
 
     /* Wrong bytestream */
@@ -296,7 +318,12 @@ parse_aac(service_t *t, elementary_stream_t *st, const uint8_t *data,
     }
   }
 
-  st->es_parser_ptr = p;
+  if (hdr && newdts != PTS_UNSET) {
+    st->es_curdts = newdts;
+    st->es_curpts = newpts;
+  }
+  if (p > 0)
+    sbuf_cut(&st->es_buf, p);
 }
 
 
@@ -549,7 +576,6 @@ static int parse_mp4a(service_t *t, elementary_stream_t *st, size_t ilen,
   return 1;
 }
 
-
 const static int mpa_br[16] = {
     0,  32,  48,  56,
    64,  80,  96, 112, 
@@ -850,7 +876,6 @@ parse_pes_header(service_t *t, elementary_stream_t *st,
     pts = getpts(buf);
     dts = getpts(buf + 5);
 
-
     d = (pts - dts) & PTS_MASK;
     if(d > 180000) // More than two seconds of PTS/DTS delta, probably corrupt
       pts = dts = PTS_UNSET;
index b18b9c7d711903d891fb07466f3a6d17bad7d2f2..f50132e9fad70986a5b919f00649ee09db92dfbc 100644 (file)
@@ -108,7 +108,7 @@ apply_header(streaming_start_component_t *ssc, th_pkt_t *pkt)
     ssc->ssc_gh = pktbuf_alloc(NULL, 2);
     uint8_t *d = pktbuf_ptr(ssc->ssc_gh);
 
-    const int profile = 2;
+    const int profile = 2; /* AAC LC */
     d[0] = (profile << 3) | ((pkt->pkt_sri & 0xe) >> 1);
     d[1] = ((pkt->pkt_sri & 0x1) << 7) | (pkt->pkt_channels << 3);
   }
index 81da7501731809521c79b2a59bc3e0add9331df8..49b90e5e92a705ce12194b3e94bde99c025768b3 100644 (file)
@@ -331,10 +331,10 @@ create_adts_header(pktbuf_t *pb, int sri, int channels)
    init_wbits(&bs, pktbuf_ptr(pb), 56);
 
    put_bits(&bs, 0xfff, 12); // Sync marker
-   put_bits(&bs, 1, 1);      // ID 0 = MPEG 4, 1 = MPEG 2
+   put_bits(&bs, 0, 1);      // ID 0 = MPEG 4, 1 = MPEG 2
    put_bits(&bs, 0, 2);      // Layer
    put_bits(&bs, 1, 1);      // Protection absent
-   put_bits(&bs, 2, 2);      // AOT, 2 = AAC LC (for MPEG 2 bit)
+   put_bits(&bs, 1, 2);      // AOT, 1 = AAC LC
    put_bits(&bs, sri, 4);
    put_bits(&bs, 1, 1);      // Private bit
    put_bits(&bs, channels, 3);
@@ -344,7 +344,7 @@ create_adts_header(pktbuf_t *pb, int sri, int channels)
    put_bits(&bs, 1, 1);      // Copyright identification bit
    put_bits(&bs, 1, 1);      // Copyright identification start
    put_bits(&bs, pktbuf_len(pb), 13);
-   put_bits(&bs, 0, 11);     // Buffer fullness
+   put_bits(&bs, 0x7ff, 11); // Buffer fullness
    put_bits(&bs, 0, 2);      // RDB in frame
 }