AAC.h 5.28 KB
Newer Older
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
3 4 5
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
9 10 11 12 13 14 15
 */

#ifndef ZLMEDIAKIT_AAC_H
#define ZLMEDIAKIT_AAC_H

#include "Frame.h"
#include "Track.h"
xiongziliang committed
16
#define ADTS_HEADER_LEN 7
17 18 19

namespace mediakit{

20 21 22
string makeAacConfig(const uint8_t *hex, int length);
int dumpAacConfig(const string &config, int length, uint8_t *out, int out_size);
bool parseAacConfig(const string &config, int &samplerate, int &channels);
23

3503207480@qq.com committed
24
/**
25 26
 * aac帧,包含adts头
 */
xiongziliang committed
27
class AACFrame : public FrameImp {
28 29
public:
    typedef std::shared_ptr<AACFrame> Ptr;
xiongziliang committed
30 31
    AACFrame(){
        _codecid = CodecAAC;
32
    }
xiongziliang committed
33
};
34

xiongziliang committed
35
class AACFrameNoCacheAble : public FrameFromPtr {
36
public:
37
    typedef std::shared_ptr<AACFrameNoCacheAble> Ptr;
38

xiongziliang committed
39
    AACFrameNoCacheAble(char *ptr,uint32_t size,uint32_t dts,uint32_t pts = 0,int prefix_size = ADTS_HEADER_LEN){
xiongziliang committed
40 41 42
        _ptr = ptr;
        _size = size;
        _dts = dts;
xiongziliang committed
43
        _prefix_size = prefix_size;
44 45 46 47 48 49 50 51 52
    }

    CodecId getCodecId() const override{
        return CodecAAC;
    }

    bool keyFrame() const override {
        return false;
    }
xiongziliang committed
53 54 55 56

    bool configFrame() const override{
        return false;
    }
xiongziliang committed
57
};
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

/**
 * aac音频通道
 */
class AACTrack : public AudioTrack{
public:
    typedef std::shared_ptr<AACTrack> Ptr;

    /**
     * 延后获取adts头信息
     * 在随后的inputFrame中获取adts头信息
     */
    AACTrack(){}

    /**
     * 构造aac类型的媒体
74
     * @param aac_cfg aac配置信息
75 76
     */
    AACTrack(const string &aac_cfg){
77 78 79 80 81 82 83 84
        setAacCfg(aac_cfg);
    }

    /**
     * 设置aac 配置信息
     */
    void setAacCfg(const string &aac_cfg){
        if (aac_cfg.size() < 2) {
xiongziliang committed
85
            throw std::invalid_argument("adts配置必须最少2个字节");
86
        }
87
        _cfg = aac_cfg;
xiongziliang committed
88
        onReady();
89 90 91
    }

    /**
92
     * 获取aac 配置信息
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
     */
    const string &getAacCfg() const{
        return _cfg;
    }

    /**
     * 返回编码类型
     */
    CodecId getCodecId() const override{
        return CodecAAC;
    }

    /**
     * 在获取aac_cfg前是无效的Track
     */
    bool ready() override {
        return !_cfg.empty();
    }

    /**
xiongziliang committed
113 114
     * 返回音频采样率
     */
115 116 117
    int getAudioSampleRate() const override{
        return _sampleRate;
    }
xiongziliang committed
118

119 120 121 122 123 124
    /**
     * 返回音频采样位数,一般为16或8
     */
    int getAudioSampleBit() const override{
        return _sampleBit;
    }
xiongziliang committed
125

126 127 128 129 130 131 132 133
    /**
     * 返回音频通道数
     */
    int getAudioChannel() const override{
        return _channel;
    }

    /**
xiongziliang committed
134 135 136
     * 输入数据帧,并获取aac_cfg
     * @param frame 数据帧
     */
137
    void inputFrame(const Frame::Ptr &frame) override{
xiongziliang committed
138
        if (_cfg.empty()) {
139
            //未获取到aac_cfg信息
140
            if (frame->prefixSize()) {
141
                //根据7个字节的adts头生成aac config
142
                _cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
143
                onReady();
xiongziliang committed
144
            } else {
145 146
                WarnL << "无法获取adts头!";
            }
147
        }
148 149 150 151 152

        if (frame->size() > frame->prefixSize()) {
            //除adts头外,有实际负载
            AudioTrack::inputFrame(frame);
        }
153 154 155 156 157
    }
private:
    /**
     * 解析2个字节的aac配置
     */
xiongziliang committed
158
    void onReady(){
xiongziliang committed
159
        if (_cfg.size() < 2) {
xiongziliang committed
160 161
            return;
        }
xiongziliang committed
162
        parseAacConfig(_cfg, _sampleRate, _channel);
163
    }
xiongziliang committed
164

165 166 167
    Track::Ptr clone() override {
        return std::make_shared<std::remove_reference<decltype(*this)>::type >(*this);
    }
xiongziliang committed
168 169 170

    //生成sdp
    Sdp::Ptr getSdp() override ;
171 172 173 174 175 176 177
private:
    string _cfg;
    int _sampleRate = 0;
    int _sampleBit = 16;
    int _channel = 0;
};

178
/**
xiongziliang committed
179 180
 * aac类型SDP
 */
181 182 183
class AACSdp : public Sdp {
public:
    /**
xiongziliang committed
184
     * 构造函数
185 186
     * @param aac_cfg aac两个字节的配置描述
     * @param sample_rate 音频采样率
xiongziliang committed
187
     * @param payload_type rtp payload type 默认98
188 189 190 191
     * @param bitrate 比特率
     */
    AACSdp(const string &aac_cfg,
           int sample_rate,
xiongziliang committed
192
           int channels,
xiongziliang committed
193 194 195
           int payload_type = 98,
           int bitrate = 128) : Sdp(sample_rate,payload_type){
        _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
196
        _printer << "b=AS:" << bitrate << "\r\n";
xiongziliang committed
197
        _printer << "a=rtpmap:" << payload_type << " MPEG4-GENERIC/" << sample_rate << "/" << channels << "\r\n";
198

199 200 201 202 203 204
        string configStr;
        char buf[4] = {0};
        for(auto &ch : aac_cfg){
            snprintf(buf, sizeof(buf), "%02X", (uint8_t)ch);
            configStr.append(buf);
        }
xiongziliang committed
205
        _printer << "a=fmtp:" << payload_type << " streamtype=5;profile-level-id=1;mode=AAC-hbr;"
xiongziliang committed
206
                 << "sizelength=13;indexlength=3;indexdeltalength=3;config=" << configStr << "\r\n";
xiongziliang committed
207
        _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
208 209 210 211 212 213 214 215 216 217 218 219 220
    }

    string getSdp() const override {
        return _printer;
    }

    CodecId getCodecId() const override {
        return CodecAAC;
    }
private:
    _StrPrinter _printer;
};

221
}//namespace mediakit
xiongziliang committed
222
#endif //ZLMEDIAKIT_AAC_H