]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
parsers: AAC - better handle SBR extension
authorJaroslav Kysela <perex@perex.cz>
Wed, 11 Feb 2015 19:59:34 +0000 (20:59 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 11 Feb 2015 19:59:34 +0000 (20:59 +0100)
src/muxer/tvh/mkmux.c
src/packet.h
src/parsers/parser_latm.c
src/parsers/parsers.c
src/plumbing/globalheaders.c
src/streaming.h

index 5f091939fb1a797f9d7a1b0829753a4b96943954..87c0800ce812986cc106e2e218e7c8b6ca7847f5 100644 (file)
@@ -57,6 +57,7 @@ typedef struct mk_track {
 
   uint8_t channels;
   uint8_t sri;
+  uint8_t ext_sri;
 
   uint16_t aspect_num;
   uint16_t aspect_den;
@@ -432,6 +433,8 @@ mk_build_tracks(mk_mux_t *mkm, const streaming_start_t *ss)
       htsbuf_queue_t *au = htsbuf_queue_alloc(0);
 
       ebml_append_float(au, 0xb5, sri_to_rate(ssc->ssc_sri));
+      if (ssc->ssc_ext_sri)
+        ebml_append_float(au, 0x78b5, sri_to_rate(ssc->ssc_ext_sri - 1));
       ebml_append_uint(au, 0x9f, ssc->ssc_channels);
       if (bit_depth)
         ebml_append_uint(au, 0x6264, bit_depth);
@@ -1215,6 +1218,7 @@ mk_mux_write_pkt(mk_mux_t *mkm, th_pkt_t *pkt)
      pkt->pkt_sri) {
     mark = 1;
     t->sri = pkt->pkt_sri;
+    t->ext_sri = pkt->pkt_ext_sri;
   }
   if(pkt->pkt_commercial != t->commercial && 
      pkt->pkt_commercial != COMMERCIAL_UNKNOWN) {
index 33b4720aba3d394211cf4036b448319faddedfe2..30d646491702df30823525eaf81bfaffae71b15a 100644 (file)
@@ -59,6 +59,7 @@ typedef struct th_pkt {
 
   uint8_t pkt_channels;
   uint8_t pkt_sri;
+  uint8_t pkt_ext_sri;
   uint8_t pkt_err;
 
   uint16_t pkt_aspect_num;
index b54170ff2f8c6eb03887494d2a9ac3da7645f744..7d013fd8cafaedd4ba2d034c9b2d67d10c1186d6 100644 (file)
@@ -43,7 +43,8 @@ typedef struct latm_private {
   int aot;
   int frame_length_type;
 
-  int sample_rate_index;
+  int sri;
+  int ext_sri;
   int channel_config;
 
 } latm_private_t;
@@ -95,25 +96,40 @@ static int
 read_audio_specific_config(elementary_stream_t *st, latm_private_t *latm,
                           bitstream_t *bs)
 {
-  int aot, sr;
+  int aot, sr, sri;
 
   if ((bs->offset % 8) != 0)
     return -1;
 
   aot = read_aot(bs);
-  sr  = read_sr(bs, &latm->sample_rate_index);
+  sr                    = read_sr(bs, &latm->sri);
   latm->channel_config  = read_bits(bs, 4);
 
+  if (sr < 7350 || sr > 96000 ||
+      latm->channel_config == 0 || latm->channel_config > 7)
+    return -1;
+
   st->es_frame_duration = 1024 * 90000 / sr;
 
+  latm->ext_sri = 0;
   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)
+    sr  = read_sr(bs, &latm->ext_sri);
+    if (sr < 7350 || sr > 96000)
+      return -1;
+    latm->ext_sri++;    // zero means "not set"
+    aot = read_aot(bs); // this is the main object type (i.e. non-extended)
+  }
+
+  /* it's really unusual to use lower sample rates than 32000Hz */
+  /* for the professional broadcasting, assume the SBR extension */
+  if (aot == AOT_AAC_LC && latm->ext_sri == 0 && sr <= 24000) {
+    sri = rate_to_sri(sr * 2);
+    if (sri < 0)
+      return -1;
+    latm->ext_sri = sri + 1;
   }
 
-  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;
@@ -121,10 +137,10 @@ read_audio_specific_config(elementary_stream_t *st, latm_private_t *latm,
 
   if (read_bits1(bs))   // framelen_flag
     return -1;
-  if (read_bits1(bs))    // depends_on_coder
+  if (read_bits1(bs))   // depends_on_coder
     skip_bits(bs, 14);
 
-  if (read_bits1(bs))    // ext_flag
+  if (read_bits1(bs))   // ext_flag
      skip_bits(bs, 1);  // ext3_flag
   return 0;
 }
@@ -250,9 +266,10 @@ parse_latm_audio_mux_element(service_t *t, elementary_stream_t *st,
   th_pkt_t *pkt = pkt_alloc(NULL, slot_len + 7, st->es_curdts, st->es_curdts);
 
   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 == 7 ? 8 : latm->channel_config;
+  pkt->pkt_duration   = st->es_frame_duration;
+  pkt->pkt_sri        = latm->sri + 1;
+  pkt->pkt_ext_sri    = latm->ext_sri;
+  pkt->pkt_channels   = latm->channel_config == 7 ? 8 : latm->channel_config;
 
   /* 7 bytes of ADTS header */
   init_wbits(&out, pktbuf_ptr(pkt->pkt_payload), 7 * 8);
@@ -262,7 +279,7 @@ parse_latm_audio_mux_element(service_t *t, elementary_stream_t *st,
   put_bits(&out, 0, 2);      // Layer
   put_bits(&out, 1, 1);      // Protection absent
   put_bits(&out, adts_aot(latm->aot), 2);
-  put_bits(&out, latm->sample_rate_index, 4);
+  put_bits(&out, latm->sri, 4);
   put_bits(&out, 1, 1);      // Private bit
   put_bits(&out, latm->channel_config, 3);
   put_bits(&out, 1, 1);      // Original
index bb1b1af8aad2bb31fcc801784236937e021924a8..082804d9810a832039feca21c641bff2233c5a4e 100644 (file)
@@ -314,6 +314,7 @@ parse_aac(service_t *t, elementary_stream_t *st, const uint8_t *data,
 
     /* Wrong bytestream */
     } else {
+      tvhtrace("parser", "AAC skip byte %02x", d[0]);
       p++;
     }
   }
index f50132e9fad70986a5b919f00649ee09db92dfbc..f330de6dc3a8b03b712dfbd8db029c42ca6f6744 100644 (file)
@@ -86,6 +86,7 @@ apply_header(streaming_start_component_t *ssc, th_pkt_t *pkt)
   if(SCT_ISAUDIO(ssc->ssc_type) && !ssc->ssc_channels && !ssc->ssc_sri) {
     ssc->ssc_channels = pkt->pkt_channels;
     ssc->ssc_sri      = pkt->pkt_sri;
+    ssc->ssc_ext_sri  = pkt->pkt_ext_sri;
   }
 
   if(SCT_ISVIDEO(ssc->ssc_type)) {
@@ -105,12 +106,17 @@ apply_header(streaming_start_component_t *ssc, th_pkt_t *pkt)
   }
 
   if (ssc->ssc_type == SCT_MP4A || ssc->ssc_type == SCT_AAC) {
-    ssc->ssc_gh = pktbuf_alloc(NULL, 2);
+    ssc->ssc_gh = pktbuf_alloc(NULL, pkt->pkt_ext_sri ? 5 : 2);
     uint8_t *d = pktbuf_ptr(ssc->ssc_gh);
 
     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);
+    if (pkt->pkt_ext_sri) { /* SBR extension */
+      d[2] = 0x56;
+      d[3] = 0xe5;
+      d[4] = 0x80 | ((pkt->pkt_ext_sri - 1) << 3);
+    }
   }
 }
 
index c7c5f0e2a069b72ed5a1cab8b4671481fbf8b701..2328ba5f2c863177acfa0b563db78dbf2da24d4d 100644 (file)
@@ -36,6 +36,7 @@ typedef struct streaming_start_component {
   int16_t ssc_aspect_num;
   int16_t ssc_aspect_den;
   uint8_t ssc_sri;
+  uint8_t ssc_ext_sri;
   uint8_t ssc_channels;
   uint8_t ssc_disabled;