
#include "AudioConverterAAC.h"

using namespace std;

namespace mfs
{
    static std::string& GetAVErrorString(int ret, std::string& message)
    {
        char buffer[256]={0};
        message = av_make_error_string(buffer,256, ret);
    }
    AudioConverterAAC::AudioConverterAAC()
    {
    }
    
    AudioConverterAAC::~AudioConverterAAC()
    {
        Stop();
    }

    int AudioConverterAAC::Stop()
    {
        // if (_oc)
        // {
        //     // 写文件尾 
        //     av_write_trailer(_oc);
        //     // 关闭输出流 
        //     avio_close(_oc->pb);
        //     // 清理封装输出上下文 
        //     avformat_free_context(_oc);
        //     _oc= nullptr;
        // }
        if (_c)
        {
            // 关闭编码器
            avcodec_close(_c);
            // 清理编码器上下文
            avcodec_free_context(&_c);
            _c= nullptr;
        }
        if (_frame)
        {
            av_frame_free(&_frame);
            _frame = nullptr;
        }
        if (_actx)
        {
            swr_free(&_actx);
            _actx = nullptr;
        }
        
        
        return 0;
    }
    void AudioConverterAAC::AddADTS(char* outdata, int packetLen)
    {
        int profile = 1; // AAC LC  
        int freqIdx = 0xb; // 44.1KHz  
        int chanCfg = CHANNELS_AUDIO; // CPE  

        auto sampleRate = SAMPLERATE_AUDIO;

        if (96000 == sampleRate)
        {
            freqIdx = 0x00;
        }
        else if(88200 == sampleRate)
        {
            freqIdx = 0x01;
        }
        else if (64000 == sampleRate)
        {
            freqIdx = 0x02;
        }
        else if (48000 == sampleRate)
        {
            freqIdx = 0x03;
        }
        else if (44100 == sampleRate)
        {
            freqIdx = 0x04;
        }
        else if (32000 == sampleRate)
        {
            freqIdx = 0x05;
        }
        else if (24000 == sampleRate)
        {
            freqIdx = 0x06;
        }
        else if (22050 == sampleRate)
        {
            freqIdx = 0x07;
        }
        else if (16000 == sampleRate)
        {
            freqIdx = 0x08;
        }
        else if (12000 == sampleRate)
        {
            freqIdx = 0x09;
        }
        else if (11025 == sampleRate)
        {
            freqIdx = 0x0a;
        }
        else if (8000 == sampleRate)
        {
            freqIdx = 0x0b;
        }
        else if (7350 == sampleRate)
        {
            freqIdx = 0xc;
        }
        // fill in ADTS data  
        outdata[0] = 0xFF;
        outdata[1] = 0xF1;
        outdata[2] = ((profile) << 6) + (freqIdx << 2) + (chanCfg >> 2);
        outdata[3] = (((chanCfg & 3) << 6) + (packetLen >> 11));
        outdata[4] = ((packetLen & 0x7FF) >> 3);
        outdata[5] = (((packetLen & 7) << 5) + 0x1F);
        outdata[6] = 0xFC;
    }
    int AudioConverterAAC::ConvertData(const uint8_t* data, int dataLength, std::vector<uint8_t>& outdata)
    {
        int ret = 0;
        std::string message;
        int samplesCount = dataLength/_perSampleBytes/_c->channels; //一帧音频存放的样本数量
        // int convertCount = 0;
        // 每次编码的采样数不能多余 编码器的frame_size
        // 如果编码器的采样格式不一样，要转换
        int encoderFrameBytes = _c->frame_size * _c->channels * _perSampleBytes;
        while (samplesCount>0)
        {
            int frameSamplesCount = samplesCount > _c->frame_size?_c->frame_size:samplesCount;
            int frameBytesCount = samplesCount > _c->frame_size?encoderFrameBytes:samplesCount * _c->channels * _perSampleBytes;

            const uint8_t* inputBuffer = data;
            int inputBufferLength = frameBytesCount;
            if(_actx)
            {
                // LOG_DEBUG << "CONVERT SAMPLEs" <<LOG_ENDL;
                // _samplesBuffer
                uint8_t *dstBuffer[1] = {_samplesBuffer.data()};
                const uint8_t *srcBuffer[1] = {data};
                ret = swr_convert(_actx, dstBuffer, frameSamplesCount, srcBuffer, frameSamplesCount);
                if (ret < 0)
                {
                    LOG_ERROR << "swr_convert error="<< GetAVErrorString(ret, message) << LOG_ENDL;
                    return -1;
                }
                inputBuffer = _samplesBuffer.data();
                inputBufferLength = _samplesBuffer.size();
            }

            // LOG_DEBUG << "send pcm:"<<inputBufferLength<<LOG_ENDL;
            // av_frame_unref(_frame);
            _frame->nb_samples = frameSamplesCount;
            ret = avcodec_fill_audio_frame(_frame, 1, _c->sample_fmt, inputBuffer, inputBufferLength, 1);
            if (ret < 0)
            {
                LOG_ERROR << "avcodec_fill_audio_frame error="<< GetAVErrorString(ret, message) << LOG_ENDL;
                return -1;
            }
            
            AVPacket pkt;
            av_init_packet(&pkt);

            // 编码
            ret = avcodec_send_frame(_c,_frame);
            if (ret!=0)
            {
                LOG_ERROR << "avcodec_send_frame error="<<GetAVErrorString(ret, message) << LOG_ENDL;
            }

            ret = avcodec_receive_packet(_c,&pkt);
            if (ret!=0 && ret!=-11)
            {
                LOG_ERROR << "avcodec_receive_packet error="<<ret<<",message:"<<GetAVErrorString(ret, message) << LOG_ENDL;
                return -1;
            }
            if (ret!=-11)
            {
                // LOG_DEBUG << "receive aac:"<<pkt.size<<LOG_ENDL;

                pkt.stream_index = 0;
                pkt.pts = 0;
                pkt.dts = 0;

                int lastSize = outdata.size();
                outdata.resize(lastSize + pkt.size+7);
                AddADTS((char*)outdata.data()+lastSize, pkt.size+7);
                memcpy(outdata.data()+lastSize+7, pkt.data, pkt.size);
            }
            else
            {
                LOG_DEBUG<<"avcodec_receive_packet ret=-11"<<LOG_ENDL;
            }
	        // av_packet_unref(&pkt);
            samplesCount -= frameSamplesCount;
            data += frameBytesCount;
        }
        
        return 0;
    } 


    void AudioConverterAAC::InitCodec()
    {
        switch (_c->codec->id)
        {
        case AV_CODEC_ID_AAC:
            _c->bit_rate = 30000;
            _c->sample_rate = SAMPLERATE_AUDIO;
            _c->sample_fmt = AV_SAMPLE_FMT_FLTP;
            _c->channel_layout = av_get_default_channel_layout(CHANNELS_AUDIO);
            _c->channels = CHANNELS_AUDIO;
            _c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            break;
        default:
            _c->bit_rate = 30000;
            _c->sample_rate = SAMPLERATE_AUDIO;
            _c->sample_fmt = AV_SAMPLE_FMT_S16;
            _c->channel_layout = AV_CH_LAYOUT_MONO;
            _c->channels = CHANNELS_AUDIO;
            _c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            break;
        }
    }

    AVCodecID AudioConverterAAC::GetCodecIDByFormat()
    {
        return AV_CODEC_ID_AAC;
    }

    int AudioConverterAAC::Start()
    {
        // av_register_all();
        // avcodec_register_all();
        
        std::string message;
        int ret = 0;
        // encoder
        AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC); // avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt, NULL, &got_frame); 
        if (!codec)
        {
            LOG_ERROR << "avcodec_find_encoder error="<<GetAVErrorString(ret, message) << LOG_ENDL;
            return -1;
        }
        _c = avcodec_alloc_context3(codec);
        if (!_c)
        {
            LOG_ERROR << "avcodec_alloc_context3 error="<< GetAVErrorString(ret, message) << LOG_ENDL;
            return -1;
        }

        InitCodec();
        
        ret = avcodec_open2(_c, codec, NULL);
        if (ret < 0)
        {
            LOG_ERROR << "avcodec_open2 error="<<GetAVErrorString(ret, message) << LOG_ENDL;
            return -1;
        }

        
        _perSampleBytes = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
        _frame = av_frame_alloc();
        _frame->format = _c->sample_fmt;
        _frame->channels = 1;
        _frame->channel_layout = AV_CH_LAYOUT_MONO;
    
        if (_c->sample_fmt != AV_SAMPLE_FMT_S16)
        {
            _samplesBuffer.resize(_c->frame_size * _c->channels * av_get_bytes_per_sample(_c->sample_fmt));
            _actx = swr_alloc_set_opts(_actx,
                _c->channel_layout, _c->sample_fmt, _c->sample_rate,//输出格式
                AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16, _c->sample_rate,//输入格式
            0,0);
            if (!_actx)
            {
                cout << "swr_alloc_set_opts error="<<GetAVErrorString(ret, message) << endl;
                getchar();
                return -1;
            }
            ret = swr_init(_actx);
            if (ret < 0)
            {
                cout << "swr_init error="<<GetAVErrorString(ret, message) << endl;
                getchar();
                return -1;
            }
        }
        
        return 0;
    }

}