0%

audio_aac_adts

AAC简介:

MPEG家族:

AAC是MPEG家族中的音频算法之一;其实AAC分了很多种://关于MPEG家族,可以看视频编码和容器流媒体概念;

  • 1991 MPEG-1 or MPEG-2 Audio Layer III,由位于德国埃尔朗根的研究组织弗劳恩霍夫协会的一组工程师发明和标准化的,它被设计来大幅降低音频数据量,通过舍弃PCM音频资料中对人类听觉不重要的部分 –MP3

  • 1997 基于MPEG-2的有损数字音频压缩的专利音频编码标准;由Fraunhofer IIS、杜比实验室、AT&T、Sony、Nokia等公司共同开发 –MPEG-2 AAC

  • 2000 MPEG-4标准在原本的基础上加上了PNS(Perceptual Noise Substitution)等技术,并提供了多种扩展工具。 –MPEG-4 AAC

  • 2003 HE-AAC v1 (aac+)

  • 2006 HE-AAC v2 (eaac+)
    于是总共有:

  • MPEG-2 AAC LC低复杂度规格(Low Complexity)

  • MPEG-2 AAC Main主规格

  • MPEG-2 AAC SSR可变采样率规格(Scaleable Sample Rate)

  • MPEG-4 AAC LC低复杂度规格(Low Complexity),现在的手机比较常见的MP4文件中的音频部分就包括了该规格音频档案

  • MPEG-4 AAC Main主规格

  • MPEG-4 AAC SSR可变采样率规格(Scaleable Sample Rate)

  • MPEG-4 AAC LTP长时期预测规格(Long Term Predicition)

  • MPEG-4 AAC LD低延迟规格(Low Delay)

  • MPEG-4 AAC HE高效率规格(High Efficiency)
    常见:MPEG-4 AAC LC(Low Complexity)是最常用的规格,我们叫“低复杂度规格”,我们简称“LC-AAC”,

    AAC 编码器:
  • FhG:Fraunhofer IIS研发的权威编码器。

  • Nero AAC:同时支持LC-AAC / HE-AAC规格,由Nero公司免费发布的Nero AAC编码器。

  • QuickTime / iTunes:Apple公司的两款软件都提供了AAC编码功能,其编码技术来自”Dolby Laboratories”(简写为Dolby Labs,杜比实验室)。

  • FAAC(Freeware Advanced Audio Coder):也是一种很好的命令行编码器,支持LC/Main/LTP规格,而这个软件是免费的。FAAC是属于自由软件。

  • DivX AAC:2009年DivX开发出来的新AAC编码器,支持LC/HE/HEv2规格。目前正在测试中。

    AAC常见的扩展名:
    1
    2
    3
    .aac
    .mp4
    .m4a

    更多历史介绍:https://zh.wikipedia.org/wiki/%E9%80%B2%E9%9A%8E%E9%9F%B3%E8%A8%8A%E7%B7%A8%E7%A2%BC

ADTS和AAC:

经验中:ADTS是aac音频文件的封装,而纯aac则可以用于流媒体传输,比如放到flv中,当然流媒体也可以传输adts.

AAC文件的封装:

通过AAC协议和文件查看 AAC Audio ES Viewer,可以看到,AAC文件是这样封装的:
ADTS header + AAC raw data ADTS header+AAC raw data ….这样;
ADTS header: adts_fixed_header() + adts_variable_header() 后者可变在于有没有包含atdt_error_check()16bit
adts_fixed_header()为固定头,是28bit, adts_variable_header() 为前面固定的28bit,加可能有的16bit tatdt_error_check()
所以ADTS header: 7(28bit+28bit)/9 Bytes(28+28+16);

ADTS头 的各个字段解释:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  Header consists of 7 or 9 bytes (without or with CRC).

Letter Length (bits) Description
A 12 syncword 0xFFF, all bits must be 1 同步号,用来找帧
B 1 MPEG Version: 0 for MPEG-4, 1 for MPEG-2 版本号
C 2 Layer: always 0 总是0
D 1 protection absent, Warning, set to 1 if there is no CRC and 0 if there is CRC 决定是否有额外16bit
E 2 profile, the MPEG-4 Audio Object Type minus 1
F 4 MPEG-4 Sampling Frequency Index (15 is forbidden) idx来表示采样,444100
G 1 private bit, guaranteed never to be used by MPEG, set to 0 when encoding, ignore when decoding
H 3 MPEG-4 Channel Configuration (in the case of 0, the channel configuration is sent via an inband PCE) channel数
I 1 originality, set to 0 when encoding, ignore when decoding
J 1 home, set to 0 when encoding, ignore when decoding 编码时设置为0,解码数据时忽略
K 1 copyrighted id bit, the next bit of a centrally registered copyright identifier, set to 0 when encoding, ignore when decoding
L 1 copyright id start, signals that this frame's copyright id bit is the first bit of the copyright id, set to 0 when encoding, ignore when decoding
M 13 frame length, this value must include 7 or 9 bytes of header length: FrameLength = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame) --帧长
O 11 Buffer fullness
P 2 Number of AAC frames (RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame --一个adts帧中的aac原始数据块数量,一般为一个
Q 16 CRC if protection absent is 0

ADTS packet must be a content of PES packet. Pack AAC data inside ADTS frame, than pack inside PES packet, then mux by TS packetizer.
aac rowdatablock:

一个典型的aac音频文件编码是这样一串:
Adts header aac rawdatablock adts header aac rawdatablock
但是首帧,可能是某种类型的rawdatablock;
关于rawdatablock
Raw_data_block格式如下,id_syn_ele:3位标志位,指示后面所跟着的数据流的类型。

在AAC中,原始数据块的组成可能有六种不同的元素:
+ SCE: Single Channel Element单通道元素。单通道元素基本上只由一个ICS组成。一个原始数据块最可能由16个SCE组成。
+ CPE: Channel Pair Element 双通道元素,由两个可能共享边信息的ICS和一些联合立体声编码信息组成。一个原始数据块最多可能由16个SCE组成。
+ CCE: Coupling Channel Element 藕合通道元素。代表一个块的多通道联合立体声信息或者多语种程序的对话信息。
+ LFE: Low Frequency Element 低频元素。包含了一个加强低采样频率的通道。
+ DSE: Data Stream Element 数据流元素,包含了一些并不属于音频的附加信息。
+ PCE: Program Config Element 程序配置元素。包含了声道的配置信息。它可能出现在 ADIF 头部信息中。
+ FIL: Fill Element 填充元素。包含了一些扩展信息。如SBR,动态范围控制信息等。
id_syn_ele 数据流

  • ID_SCE(0x0) single_channel_element()
  • ID_CPE(0x1)channel_pair_element()
  • ID_CCE(0x2)coupling_channel_element()
  • ID_LFE(0x3)lfe_channel_element(
  • ID_DSE(0x4)data_stream_element()
  • ID_PCE(0x5)program_config_element()
  • ID_FIL(0x6)fill_element()
ref:

more:https://www.cnblogs.com/fellow1988/p/7291939.html
https://maxwellqi.github.io/ios-audio-format-decoder/
http://www.telemidia.puc-rio.br/~rafaeldiniz/public_files/normas/ISO-13818/ISO_IEC_13818-7_2006(E).pdf

关于buffer fullness:http://blog.olivierlanglois.net/index.php/2008/09/12/aac_adts_header_buffer_fullness_field

FLV中AAC的封装:

FlV由tag构成,而音频的tag是:包含AAC头的tag+ 后面都是AAC 原始数据的tag
11B tag header + 2B audio tag header + 一般是5B的AAC sequence header;
之后就都是数据:11B头+2B音频tag头+aac rawdata==(adts中的aac rawdatablock)
通过flvAnalyser工具可以看到:

更多见flv的封装;和https://wiki.multimedia.cx/index.php/MPEG-4_Audio

如何将flv aac封装为流媒体: 举例:

一般来讲,流媒体传输需要使得最终接收方可以解码播放,所以需要传递解码信息,如音频必备的几个要素:channel,samplaterate,编码方式等等,而版权等根据需要放入metadata

http://www.telemidia.puc-rio.br/~rafaeldiniz/public_files/normas/ISO-13818/ISO_IEC_13818-7_2006%28E%29.pdf
ISO_IEC_13818-7_2006(E).pdf MPEG-2的AAC
ISO14496-3-2009.pdf MPEG-4的AAC
HE-AAC: trev_305-moser.pdf

代码:

一个解析aac文件的简单程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/env python3                                                                                                                                                                                     
2 import sys
3 import struct
4
5 if len(sys.argv) < 2:
6 print("Usage: aac_parer.py <target.aac>")
7 exit()
8
9 aacfile = open(sys.argv[1], 'rb')
10 frame_no = 1
11
12 while True:
13 data = aacfile.read(7)
14 if not data:
- 15 exit()
16 hdr = struct.unpack(">7B", data)
17
18 # parse adts_fixed_header()
19 syncword = (hdr[0] << 4) | (hdr[1] >> 4) # bslbf(12)
20 if syncword != 0b111111111111:
- 21 print("Invalid `syncword` for {} frame".format(frame_no))
| 22 exit()
23 ID = (hdr[1] >> 3) & 0b1 # bslbf(1)
24 layer = (hdr[1] >> 1) & 0b11 # uimsbf(2)
25 protection_absent = (hdr[1] ) & 0b1 # bslbf(1)
26 profile = (hdr[2] >> 6) & 0b11 # uimsbf(2)
27 sampling_freq_idx = (hdr[2] >> 2) & 0b1111 # uimsbf(4)
28 private_bit = (hdr[2] >> 1) & 0b1 # bslbf(1)
29 channel_cfg = ((hdr[2] & 0b1) << 2) | (hdr[3] >> 6) # uimsbf(3)
30 original_copy = (hdr[3] >> 5) & 0b1 # bslbf(1)
31 home = (hdr[3] >> 4) & 0b1 # bslbf(1)
32 # parse adts_variable_header()
33 copyright_id_bit = (hdr[3] >> 3) & 0b1 # bslbf(1)
34 copyright_id_start = (hdr[3] >> 2) & 0b1 # bslbf(1)
35 frame_length = ((hdr[3] & 0b11) << 11) | (hdr[4] << 3) | (hdr[5] >> 5) # bslbf(13)
36 adts_buf_fullness = ((hdr[5] & 0b11111) << 6) | (hdr[6] >> 2) # bslbf(11)
37 num_rawdata_blocks = (hdr[6] ) & 0b11 # uimsbf(2)
38
39 crc_check = 0
40 size = frame_length - 7
41 if num_rawdata_blocks == 0:
42 # adts_error_check()
43 if protection_absent == 0:
| 44 ¦ crc_check = struct.unpack(">H", aacfile.read(2))[0] # rpchof(16)
| 45 ¦ size -= 2
| 46 # raw_data_block()
| 47 aacfile.read(size)
48 else:
49 # adts_header_error_check()
- 50 if protection_absent == 0:
| 51 ¦ crc_check = struct.unpack(">H", aacfile.read(2))[0] # rpchof(16)
| 52 ¦ size -= (2 * num_rawdata_blocks) + 2
| 53 # {raw_data_block() + adts_raw_data_block_error_check()} x N
| 54 aacfile.read(size)
55 print("raw size:")
56 print(size)
57 if frame_no >= 1:
58 # dump adts_fixed_header()
- 59 print("adts_fixed_header():")
| 60 print("ID={}".format(ID))
| 61 print("layer={:02b}".format(layer))
| 62 print("protection_absent={}".format(protection_absent))
| 63 print("profile={}".format(profile))
| 64 print("sampling_frequency_index=0x{:x}".format(sampling_freq_idx))
| 65 print("private_bit={}".format(private_bit))
| 66 print("channel_configuration={}".format(channel_cfg))
| 67 print("original/copy={}".format(original_copy))
| 68 print("home={}".format(home))
| 69 print("adts_variable_header():")
| 70 # dump adts_variable_header()
| 71 print("#{},{},{},{},{},{},0x{:04x}".format(
| 72 frame_no, copyright_id_bit, copyright_id_start, frame_length, adts_buf_fullness, num_rawdata_blocks, crc_check))
73 frame_no += 1