#include "aac.h"

#include "bitStream.h"
#include "vod_common.h"

const int AACCodec::aac_sample_rates[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000,
                                            22050, 16000, 12000, 11025, 8000,  7350};

const int AACCodec::aac_channels[8] = {0, 1, 2, 3, 4, 5, 6, 8};

uint8_t* AACCodec::findAacFrame(uint8_t* buffer, uint8_t* end)
{
    uint8_t* curBuf = buffer;
    while (curBuf < end)
    {
        if (*curBuf < 0xf0)
            curBuf += 2;
        else if (*curBuf == 0xff && curBuf < end - 1 && (curBuf[1] & 0xf6) == 0xf0)
            return curBuf;
        else if ((*curBuf & 0xf6) == 0xf0 && curBuf > buffer && curBuf[-1] == 0xff)
            return curBuf - 1;
        else
            curBuf++;
    }
    return 0;
}

int AACCodec::getFrameSize(uint8_t* buffer) { return ((buffer[3] & 0x03) << 11) + (buffer[4] << 3) + (buffer[5] >> 5); }

bool AACCodec::decodeFrame(uint8_t* buffer, uint8_t* end)
{
    BitStreamReader bits{};
    try
    {
        bits.setBuffer(buffer, end);
        if (bits.getBits(12) != 0xfff)  // sync bytes
            return false;

        m_id = bits.getBit();      /* 0: MPEG-4, 1: MPEG-2*/
        m_layer = bits.getBits(2); /* layer */
        bits.skipBit();            /* protection_absent */
        // -- 16 bit
        m_profile = bits.getBits(2);            /* profile_objecttype */
        m_sample_rates_index = bits.getBits(4); /* sample_frequency_index */
        if (!aac_sample_rates[m_sample_rates_index])
            return false;
        bits.skipBit();                     /* private_bit */
        m_channels_index = bits.getBits(3); /* channel_configuration */
        if (!aac_channels[m_channels_index])
            return false;
        bits.skipBit(); /* original/copy */
        bits.skipBit(); /* home */

        /* adts_variable_header */
        bits.skipBit();                   /* copyright_identification_bit */
        bits.skipBit();                   /* copyright_identification_start */
        int frameSize = bits.getBits(13); /* aac_frame_length */
        bits.skipBits(11);                /* adts_buffer_fullness */
        m_rdb = bits.getBits(2);          /* number_of_raw_data_blocks_in_frame */

        m_channels = aac_channels[m_channels_index];
        m_sample_rate = aac_sample_rates[m_sample_rates_index];
        m_samples = (m_rdb + 1) * 1024;
        m_bit_rate = frameSize * 8 * m_sample_rate / m_samples;
        return true;
    }
    catch (BitStreamException e)
    {
        (void)e;
        return NOT_ENOUGH_BUFFER;
    }
}

void AACCodec::buildADTSHeader(uint8_t* buffer, int frameSize)
{
    BitStreamWriter writer{};
    writer.setBuffer(buffer, buffer + AAC_HEADER_LEN);
    writer.putBits(12, 0xfff);
    writer.putBit(m_id);
    writer.putBits(2, m_layer);
    writer.putBit(1);  // protection_absent
    writer.putBits(2, m_profile);
    m_sample_rates_index = 0;
    for (int i = 0; i < 16; i++)
        if (aac_sample_rates[i] == m_sample_rate)
        {
            m_sample_rates_index = i;
            break;
        }
    writer.putBits(4, m_sample_rates_index);
    writer.putBit(0); /* private_bit */
    m_channels_index = 0;
    for (int i = 0; i < 8; i++)
        if (aac_channels[i] == m_channels)
        {
            m_channels_index = i;
            break;
        }
    writer.putBits(3, m_channels_index);

    writer.putBit(0); /* original/copy */
    writer.putBit(0); /* home */

    /* adts_variable_header */
    writer.putBit(0); /* copyright_identification_bit */
    writer.putBit(0); /* copyright_identification_start */

    writer.putBits(13, frameSize);  // /* aac_frame_length */
    writer.putBits(11, 2047);       // /* adts_buffer_fullness */
    writer.putBits(2, m_rdb);       /* number_of_raw_data_blocks_in_frame */
    writer.flushBits();
}

void AACCodec::readConfig(uint8_t* buff, int size)
{
    BitStreamReader reader{};
    reader.setBuffer(buff, buff + size);
    int object_type = reader.getBits(5);
    if (object_type == 31)
        object_type = 32 + reader.getBits(6);
    m_profile = (object_type & 0x3) - 1;
    m_sample_rates_index = reader.getBits(4);
    m_sample_rate = m_sample_rates_index == 0x0f ? reader.getBits(24) : aac_sample_rates[m_sample_rates_index];
    m_channels_index = reader.getBits(4);
    m_channels = aac_channels[m_channels_index];
    // return specific_config_bitindex;
}
