AAC码流解析

1. AAC格式介绍

高级音频编码AAC(Advanced Audio Coding)有两种封装格式,音频数据交换格式ADIF(Audio Data Interchange Format)和音频数据传输流ADTS(Audio Data Transport Stream)。二者的区别主要是:

  1. ADIF只有一个头部,只能在开始的位置进行解码,主要用于本地存储;
  2. ADTS的每个帧都有一个头部,可以在音频流的任意位置进行解码,常用于流媒体传输。

现在用的比较多的主要是ADTS,接下来介绍一下ADTS的结构。

AAC原始码流是由一个个ADTS帧组成的,其结构如下图:

ADTS_Header大小为一般是7个字节,如果需要对数据进行CRC校验,则会多出2个字节的校验码,那么长度则为9字节,里面包含了采样率、通道数、压缩级别以及帧长度等信息。ADTS_Header分为固定头部和可变头部,均为28bits。固定头部在帧与帧之间是一样的,而可变头部在帧与帧之间可能不同。

接下来介绍一下固定头部的信息。

Syntax

No. of bits

Meaning

Syncword

12

同步字,固定为0xFFF,表示帧开始

ID

1

MPEG标识符,0表示MPEG-4,1表示MPEG-2

layer

2

总是00

protection_absent

1

是否无码校验(CRC),0表示有码,1表示无码

profile

2

使用哪个级别的AAC,级别越高压缩率越大

sampling_frequency_index

4

采样率索引

private_bit

1

是否存在私有数据

channel_configuration

3

声道数

original_copy

1

表示原始音频数据是否进行了拷贝,为1表示该音频数据是原始的,为0表示该音频数据是经过拷贝的

home

1

接下来介绍一下AAC级别索引表。

index

profile

0

Main profile

1

Low Complexity profile (LC)

2

Scalable Sampling Rate profile (SSR)

3

(reserved)

接下来介绍一下采样率索引表。 

sampling_frequency_index

value

0x0

96000 Hz

0x1

88200 Hz

0x2

64000 Hz

0x3

48000 Hz

0x4

44100 Hz

0x5

32000 Hz

0x6

24000 Hz

0x7

22050 Hz

0x8

16000 Hz

0x9

12000 Hz

0xa

11025Hz

0xb

8000 Hz

0xc

7350 Hz

0xd

reserved

0xe

reserved

0xf

escape value

 接下来介绍一下可变头部的信息。

Syntax

No. of bits

Meaning

copyright_identification_bit

1

音频数据是否受到版权保护

copyright_identification_start

1

编码默认值为0,解码忽略此值

aac_frame_length

13

ADTS帧长度,包括ADTS_Header和AAC_ES

adts_buffer_fullness

11

默认是0x7FF,表示码率可变的码流

number_of_raw_data_blocks_in_frame

2

表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始数据块

 2. 代码实现

#include <stdio.h>
#include <stdint.h>
#include <string.h>

typedef struct AAC_ADTS_Header
{
    uint8_t profile;
    uint8_t sampling_frequency_index;
    uint8_t channel_configuration;
    uint16_t aac_frame_length;
}AAC_ADTS_Header;

int main()
{
    FILE *in_fp = fopen("test.aac", "rb");
    if (!in_fp)
    {
        printf("%s\n", "open file error");
        return -1;
    }

    char header[7];
    char aac_es[4096];
    size_t nread = 0;
    AAC_ADTS_Header aac_adts_header;
    while (!feof(in_fp))
    {
        memset(header, 0, sizeof(header));
        memset(aac_es, 0, sizeof(aac_es));
        memset(&aac_adts_header, 0, sizeof(aac_adts_header));
        nread = fread(header, 1, sizeof(header), in_fp);
        if (nread != sizeof(header))
        {
            if (feof(in_fp))
            {
                fclose(in_fp);
                return 0;
            }
            printf("%s\n", "read header failed");
        }

        aac_adts_header.profile = ((header[2] & 0xc0) >> 6);
        aac_adts_header.sampling_frequency_index = ((header[2] & 0x3c) >> 2);
        aac_adts_header.channel_configuration = (((header[2] & 0x01) << 2) | ((header[3] & 0xc0) >> 6));
        aac_adts_header.aac_frame_length = (header[3] & 0x03);
        aac_adts_header.aac_frame_length <<= 8;
        aac_adts_header.aac_frame_length |= header[4];
        aac_adts_header.aac_frame_length <<= 3;
        aac_adts_header.aac_frame_length |= ((header[5] & 0xe0) >> 5);

        nread = fread(aac_es, 1, aac_adts_header.aac_frame_length - sizeof(header), in_fp);
        if (nread != aac_adts_header.aac_frame_length - sizeof(header))
        {
            printf("%s\n", "read aac audio stream failed");
            return -1;
        }

        printf("profile: %d, sampling_frequency_index: %d, channel_configuration: %d, aac_frame_length: %d\n", aac_adts_header.profile,
        aac_adts_header.sampling_frequency_index, aac_adts_header.channel_configuration, aac_adts_header.aac_frame_length);
    }

    fclose(in_fp);
    return 0;
}

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值