]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Initial support for parsing AAC streams inside mp4a container
authorJernej Fijačko <jernej@jernej-ThinkCentre-M91p.(none)>
Thu, 15 Sep 2011 13:12:54 +0000 (15:12 +0200)
committerJernej Fijačko <jernej@jernej-ThinkCentre-M91p.(none)>
Thu, 15 Sep 2011 13:12:54 +0000 (15:12 +0200)
src/parsers.c
src/psi.c
src/service.c
src/tvheadend.h

index 9b7337dcb5b042a2308a03bd79ea40af4ed76e42..d6538aeb0630e9e8d9653ce7ab9a5c5fb689309b 100644 (file)
@@ -113,6 +113,9 @@ static int parse_ac3(service_t *t, elementary_stream_t *st, size_t len,
 static int parse_eac3(service_t *t, elementary_stream_t *st, size_t len,
                      uint32_t next_startcode, int sc_offset);
 
+static int parse_mp4a(service_t *t, elementary_stream_t *st, size_t ilen,
+         uint32_t next_startcode, int sc_offset);
+
 static void parser_deliver(service_t *t, elementary_stream_t *st, th_pkt_t *pkt);
 
 static int parse_pes_header(service_t *t, elementary_stream_t *st,
@@ -150,6 +153,10 @@ parse_mpeg_ts(service_t *t, elementary_stream_t *st, const uint8_t *data,
     parse_sc(t, st, data, len, parse_eac3);
     break;
 
+  case SCT_MP4A:
+    parse_sc(t, st, data, len, parse_mp4a);
+    break;
+
   case SCT_DVBSUB:
     parse_subtitles(t, st, data, len, start);
     break;
@@ -263,9 +270,6 @@ parse_aac(service_t *t, elementary_stream_t *st, const uint8_t *data,
 }
 
 
-
-
-
 /**
  * Generic video parser
  *
@@ -429,7 +433,80 @@ makeapkt(service_t *t, elementary_stream_t *st, const void *buf,
   st->es_curdts = PTS_UNSET;
   st->es_nextdts = dts + duration;
 }
-         
+
+/**
+ * Parse AAC MP4A
+ */
+
+static const int aac_sample_rates[12] = 
+{ 
+       96000, 
+       88200, 
+       64000, 
+       48000, 
+       44100,
+       32000, 
+       24000, 
+       22050, 
+       16000, 
+       12000, 
+       11025, 
+       8000
+};
+
+/**
+ * Inspect ADTS header
+ */
+static int
+mp4a_valid_frame(const uint8_t *buf)
+{
+  return (buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0);
+}
+
+static int parse_mp4a(service_t *t, elementary_stream_t *st, size_t ilen,
+         uint32_t next_startcode, int sc_offset)
+{
+  int i, len;
+  const uint8_t *buf;
+
+  if((i = depacketize(t, st, ilen, next_startcode, sc_offset)) != 0)
+    return i;
+
+ again:
+  buf = st->es_buf_a.sb_data;
+  len = st->es_buf_a.sb_ptr;
+
+  for(i = 0; i < len - 6; i++) {
+    const uint8_t *p = buf + i;
+    if(mp4a_valid_frame(p)) {
+
+      int fsize     = ((p[3] & 0x03) << 11) | (p[4] << 3) | ((p[5] & 0xe0) >> 5);
+      int sr_index = (p[2] & 0x3c) >> 2;
+      int sr = aac_sample_rates[sr_index];
+
+      
+      if(sr) {
+       int duration = 90000 * 1536 / sr;
+       int64_t dts = st->es_curdts;
+       int sri = rate_to_sri(sr);
+
+       if(dts == PTS_UNSET)
+         dts = st->es_nextdts;
+
+       if(dts != PTS_UNSET && len >= i + fsize + 6 &&
+          mp4a_valid_frame(p + fsize)) {
+
+         int channels = ((p[2] & 0x01) << 2) | ((p[3] & 0xc0) >> 6);
+
+         makeapkt(t, st, p, fsize, dts, duration, channels, sri);
+         sbuf_cut(&st->es_buf_a, i + fsize);
+         goto again;
+       }
+      }
+    }
+  }
+  return 1;
+}        
 
 
 const static int mpa_br[16] = {
index 5c792a58d5a0d1ada5fc36fa5a0336eb36719578..51831d063a06ba7a5d74dac2a460a88e65e061fa 100644 (file)
--- a/src/psi.c
+++ b/src/psi.c
@@ -519,6 +519,10 @@ psi_parse_pmt(service_t *t, const uint8_t *ptr, int len, int chksvcid,
     case 0x81:
       hts_stream_type = SCT_AC3;
       break;
+    
+    case 0x0f:
+      hts_stream_type = SCT_MP4A;
+      break;
 
     case 0x11:
       hts_stream_type = SCT_AAC;
@@ -568,7 +572,9 @@ psi_parse_pmt(service_t *t, const uint8_t *ptr, int len, int chksvcid,
        break;
 
       case DVB_DESC_AAC:
-       if(estype == 0x11)
+       if(estype == 0x0f)
+         hts_stream_type = SCT_MP4A;
+       else if(estype == 0x11)
          hts_stream_type = SCT_AAC;
        break;
 
@@ -592,7 +598,6 @@ psi_parse_pmt(service_t *t, const uint8_t *ptr, int len, int chksvcid,
       }
       len -= dlen; ptr += dlen; dllen -= dlen;
     }
-
     
     if(hts_stream_type == SCT_UNKNOWN && estype == 0x06 &&
        pid == 3401 && t->s_dvb_service_id == 10510) {
@@ -736,6 +741,7 @@ psi_build_pmt(streaming_start_t *ss, uint8_t *buf0, int maxlen, int pcrpid)
       c = 0x06;
       break;
 
+    case SCT_MP4A:
     case SCT_AAC:
       c = 0x11;
       break;
@@ -764,6 +770,7 @@ psi_build_pmt(streaming_start_t *ss, uint8_t *buf0, int maxlen, int pcrpid)
 
     switch(ssc->ssc_type) {
     case SCT_MPEG2AUDIO:
+    case SCT_MP4A:
     case SCT_AAC:
       buf[0] = DVB_DESC_LANGUAGE;
       buf[1] = 4;
@@ -886,6 +893,7 @@ static struct strtab streamtypetab[] = {
   { "MPEGTS",     SCT_MPEGTS },
   { "TEXTSUB",    SCT_TEXTSUB },
   { "EAC3",       SCT_EAC3 },
+  { "MP4A",       SCT_MP4A },
 };
 
 
index b7eec88131fa9460f1cbb539c3da0ee5611da1c9..6cba2da78afb7b3b93a690af743c7ef1adc0380b 100644 (file)
@@ -605,6 +605,7 @@ service_stream_create(service_t *t, int pid,
 
   st = calloc(1, sizeof(elementary_stream_t));
   st->es_index = idx + 1;
+
   st->es_type = type;
 
   TAILQ_INSERT_TAIL(&t->s_components, st, es_link);
@@ -854,6 +855,12 @@ service_build_stream_start(service_t *t)
     streaming_start_component_t *ssc = &ss->ss_components[n++];
     ssc->ssc_index = st->es_index;
     ssc->ssc_type  = st->es_type;
+
+    // Jernej says: I don't know how else?!
+    if (ssc->ssc_type == SCT_MP4A) {
+      ssc->ssc_type = SCT_AAC;
+    }
+
     memcpy(ssc->ssc_lang, st->es_lang, 4);
     ssc->ssc_composition_id = st->es_composition_id;
     ssc->ssc_ancillary_id = st->es_ancillary_id;
index 4dd4e2b9cc5ac8a6b90754243e9cfa52a882b155..a73b66619d38af6631c320c34f161369e97a9dc2 100644 (file)
@@ -163,11 +163,12 @@ typedef enum {
   SCT_MPEGTS,
   SCT_TEXTSUB,
   SCT_EAC3,
+  SCT_MP4A,
 } streaming_component_type_t;
 
 #define SCT_ISVIDEO(t) ((t) == SCT_MPEG2VIDEO || (t) == SCT_H264)
 #define SCT_ISAUDIO(t) ((t) == SCT_MPEG2AUDIO || (t) == SCT_AC3 || \
-                        (t) == SCT_AAC)
+                        (t) == SCT_AAC || (t) == SCT_MP4A)
 
 /**
  * The signal status of a tuner