Decoding AAC CPE

From MultimediaWiki
Revision as of 17:20, 5 March 2006 by Multimedia Mike (talk | contribs) (import cursory CPE decoder pseudocode)
Jump to navigation Jump to search

Part of Understanding AAC

A CPE is a channel pair element. This element contains the encoded data for 2 audio channels which probably have data in common. Presently, this description is only concerned with what it takes to decode low complexity (LC) data and processing that affects other features is skipped (except if the data needs to be parsed from the bitstream).

A note about this ad-hoc conventions in this syntax description: This notation:

foo: 6 bits

indicates that the next 6 bits are to be read from the bitstream and stored in variable foo. Similarily, this notation:

bar: foo

indicates that the next (foo) quantity bits are to be read from the bitstream and stored in variable bar.

Function Hierarchy

When FAAD2 wants to decode a CPE, this is the sequence of functions it calls in its internal hierarchy:

syntax.c:decode_cpe()
 +-syntax.c:channel_pair_element()
    +-syntax.c:ics_info()
      +-specrec.c:window_grouping_info()
    +-syntax.c:ltp_data() (only for LTP decoding)
    +-syntax.c:individual_channel_stream()
      +-syntax.c:ics_info()
      +-syntax.c:section_data()
      +-syntax.c:scale_factor_data()
        +-rvlc.c:decode_scale_factors()
      +-syntax.c:pulse_data()
      +-syntax.c:tns_data()
      +-syntax.c:gain_control_data() (for SSR decoding)
      +-rvlc.c:rvlc_decode_scale_factors()
      +-hcr.c:reordered_spectral_data()
      +-syntax.c:spectral_data()
        +-huffman.c:huffman_spectral_data()
      +-pulse.c:pulse_decode()
    +-specrec.c:reconstruct_channel_pair()

decode_cpe

 channel_pair_element()

channel_pair_element

 declare 2 ic_stream structures: ics1 and ics2
 1 bit:  element_instance_tag
 1 bit:  common_window
 if 1 then both channels have common ics information
   ics_info(ics1)
   2 bits: ics1.ms_mask_present
   if ics1.ms_mask_present is 1
     foreach g in 0..ics1.num_windows_groups-1
       foreach sfb in 0..ics.max_sfb-1
          1 bit: ics.ms_used[g][sfb]
   // error resilience stuff
   copy ics1 into ics2
 else
   ics1.ms_mask_present = 0
 individual_channel_stream(ics1)
 // error resilience stuff
 individual_channel_stream(ics2)
 // SBR stuff
 reconstruct_channel_pair(ics1, ics2)

ics_info(ic_stream ics)

 1 bit:  reserved
 2 bits: ics.window_sequence
 1 bit:  ics.window_shape
   #define ONLY_LONG_SEQUENCE   0x0
   #define LONG_START_SEQUENCE  0x1
   #define EIGHT_SHORT_SEQUENCE 0x2
   #define LONG_STOP_SEQUENCE   0x3
 if ics.window_sequence = EIGHT_SHORT_SEQUENCE
   4 bits: ics.max_sfb
   7 bits: ics.scale_factor_grouping
 else
   6 bits: ics.max_sfb
 window_grouping_info(ics)
 if ics.max_sfb > ics.num_swb
   error
 if ics.window_sequence != EIGHT_SHORT_SEQUENCE
   1 bit: ics.predictor_data_present
   if ics.predictor_data_present = 1
     // main profile stuff
     // LTP stuff
     // ER stuff

window_sequence(ic_stream ics)

 if ics.window_sequence is 0, 1, or 2
   ics.num_windows = 1
   ics.num_window_groups = 1
   ics.window_group_length[ics.num_window_groups - 1] = 1
   if aac_object_type is LD
     if frame_length is 512
       ics.num_swb = num_swb_512_window[sf_index]
     else
       ics.num_swb = num_swb_480_window[sf_index]
   else
     if frame_length is 1024
       ics.num_swb = num_swb_1024_window[sf_index]
     else
       ics.num_swb = num_swb_960_window[sf_index]
   if aac_object_type is LD
     if frame_length is 512
       foreach i in 0..ics.num_swb-1
         ics.sect_sfb_offset[0][i] = swb_offset_512_window[sf_index][i]
         ics.swb_offset[i] = swb_offset_512_window[sf_index][i]
     else
       foreach i in 0..ics.num_swb-1
         ics.sect_sfb_offset[0][i] = swb_offset_480_window[sf_index][i]
         ics.swb_offset[i] = swb_offset_480_window[sf_index][i]
     ics.sect_sfb_offset[0][ics.num_swb] = frameLength;
     ics.swb_offset[ics.num_swb] = frameLength;
   else
     foreach i in 0..ics.num_swb-1
       ics.sect_sfb_offset[0][i] = swb_offset_1024_window[sf_index][i]
       ics.swb_offset[i] = swb_offset_1024_window[sf_index][i]
     ics.sect_sfb_offset[0][ics.num_swb] = frameLength
     ics.swb_offset[ics.num_swb] = frameLength;
  else (ics.window_sequence is 3) { EIGHT_SHORT_SEQUENCE }
    ics.num_windows = 1
    ics.num_window_groups = 1
    ics.window_group_length[ics.num_window_groups - 1] = 1
    ics.num_swb = num_swb_128_window[sf_index]
    foreach i in 0..ics.num_swb-1
      ics.sect_sfb_offset[0][i] = swb_offset_128_window[sf_index][i]
    ics.swb_offset[ics.num_swb] = frameLength / 8
    foreach i in 0..ics.num_windows-1
      if bit #6-i in ics.scale_factor_grouping is set
        ics.num_windows>groups++
        ics.window_group_length[ics.num_window_groups - 1] = 1
      else
        ics.window_group_length[ics.num_window_groups - 1]++
    foreach g in 0..ics.num_window_groups
      declare local_width
      declare local_sect_sfb = 0
      declare local_offset = 0
      foreach i in ics.num_swb
        if i + 1 == ics.num_swb
          width = frameLength / 8 - swb_offset_128_window[sf_index][i]
        else
          width = swb_offset_128_window[sf_index][i+1] - swb_offset_128_window[sf_index][i]
        width *= ics.window_group_length[g]
        ics.sect_sfb_offset[g][sect_sfb++] = offset
        offset += width
      ics.sect_sfb_offset[g][sect_sfb] = offset;

individual_channel_stream(ic_stream ics)

 8 bits: ics.global_gain
 do ics_info process if both element.common_window and scal_flag are 0
 section_data(ics)
 scale_factor_data(ics)
 if scal_flag is 0
   1 bit: pulse_data_present
   if pulse_data_present is 1
     pulse_data(ics)
   1 bit: tns_data_present
   if tns_data_present
     tns_data(ics)
   1 bit: gain_control_data_present
   if gain_control_data_present
     if object_type is SSR
       gain_control_data(ics)
 // error resilience and DRM stuff
 spectral_data(ics)
 if pulse_data_present
   if ics.window_sequence == EIGHT_SHORT_SEQUENCE
     error
   else
     pulse_decode(ics)

section_data(ic_stream ics)

 if ics.window_sequence = EIGHT_SHORT_SEQUENCE
   section_bits = 3
 else
   section_bits = 5
 section_escape_value = (1 << section_bits) - 1 (either 7 or 31/0x1F)
 foreach g in 0..ics.num_window-groups-1
   k = i = 0
   // remember to check that the following loop is not stuck
   while k < ics.max_sfb
     if aacSectionDataResilienceFlag
       section_codebook_bits = 5
     else
       section_codebook_bits = 4
     section_codebook_bits: ics.section_codebook[g][i]
     if ics.section_codebook[g][i] = NOISE_HCB // 13
       ics.noise_used = 1
     // error resilience stuff
     section_bits: section_length_increment
     while section_length_increment = section_escape_value
       section_length += section_length_increment
       section_bits: section_length_increment
     section_length += section_length_increment
     ics.section_start[g][i] = k
     ics.section_end[g][i] = k
     if k + section_length >= 8*15
       error
     if i >= 8*15
       error
     foreach sfb = k..k+section_length-1
       ics.sfb_codebook[g][sfb] = ics.section_codebook[g][i]
     k += section_length
     i++