/*
*
* Copyright 2015 Rockchip Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <stdlib.h>
#include <string.h>

#include "h264d_scalist.h"



static RK_U8 ZZ_SCAN[16] =
{ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 };

static RK_U8 ZZ_SCAN8[64] = {
    0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
    12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
    35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
    58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};

static RK_S32 Default4x4Intra[H264ScalingList4x4Length] =
{ 6, 13, 20, 28, 13, 20, 28, 32, 20, 28, 32, 37, 28, 32, 37, 42 };

static RK_S32 Default4x4Inter[H264ScalingList4x4Length] =
{ 10, 14, 20, 24, 14, 20, 24, 27, 20, 24, 27, 30, 24, 27, 30, 34 };

static RK_S32 Default8x8Intra[H264ScalingList8x8Length] = {
    6, 10, 13, 16, 18, 23, 25, 27, 10, 11, 16, 18, 23, 25, 27, 29,
    13, 16, 18, 23, 25, 27, 29, 31, 16, 18, 23, 25, 27, 29, 31, 33,
    18, 23, 25, 27, 29, 31, 33, 36, 23, 25, 27, 29, 31, 33, 36, 38,
    25, 27, 29, 31, 33, 36, 38, 40, 27, 29, 31, 33, 36, 38, 40, 42
};

static RK_S32 Default8x8Inter[H264ScalingList8x8Length] = {
    9, 13, 15, 17, 19, 21, 22, 24, 13, 13, 17, 19, 21, 22, 24, 25,
    15, 17, 19, 21, 22, 24, 25, 27, 17, 19, 21, 22, 24, 25, 27, 28,
    19, 21, 22, 24, 25, 27, 28, 30, 21, 22, 24, 25, 27, 28, 30, 32,
    22, 24, 25, 27, 28, 30, 32, 33, 24, 25, 27, 28, 30, 32, 33, 35
};

static RK_S32 Default4x4[16] =
{ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 };

static RK_S32 Default8x8[64] = {
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
};


static void set_sps_scanlist_matrix(H264_SPS_t *sps, H264dVideoCtx_t *p_Vid)
{
    RK_S32 i = 0;

    for (i = 0; i < 6; ++i) {
        if (!sps->seq_scaling_list_present_flag[i]) { // fall-back rule A
            if (i == 0) {
                p_Vid->qmatrix[i] = Default4x4Intra;
            } else if (i == 3) {
                p_Vid->qmatrix[i] = Default4x4Inter;
            } else {
                p_Vid->qmatrix[i] = p_Vid->qmatrix[i - 1];
            }
        } else {
            if (sps->UseDefaultScalingMatrix4x4Flag[i]) {

                p_Vid->qmatrix[i] = (i < 3) ? Default4x4Intra : Default4x4Inter;
            } else {
                p_Vid->qmatrix[i] = sps->ScalingList4x4[i];
            }
        }
    }

    for (i = 6; i < ((sps->chroma_format_idc != H264_CHROMA_444) ? 8 : 12); ++i) {
        if (!sps->seq_scaling_list_present_flag[i]) { // fall-back rule A
            if (i == 6) {
                p_Vid->qmatrix[i] = Default8x8Intra;
            } else if (i == 7) {
                p_Vid->qmatrix[i] = Default8x8Inter;
            } else {
                p_Vid->qmatrix[i] = p_Vid->qmatrix[i - 2];
            }
        } else {
            if (sps->UseDefaultScalingMatrix8x8Flag[i - 6]) {

                p_Vid->qmatrix[i] = (i == 6 || i == 8 || i == 10) ? Default8x8Intra : Default8x8Inter;
            } else {
                p_Vid->qmatrix[i] = sps->ScalingList8x8[i - 6];
            }
        }
    }
}

static void set_pps_scanlist_matrix(H264_SPS_t *sps, H264_PPS_t *pps, H264dVideoCtx_t *p_Vid)
{
    RK_S32 i = 0;

    for (i = 0; i < 6; ++i) {
        if (!pps->pic_scaling_list_present_flag[i]) { // fall-back rule B
            if (i == 0) {
                if (!sps->seq_scaling_matrix_present_flag) {
                    p_Vid->qmatrix[i] = Default4x4Intra;
                }
            } else if (i == 3) {
                if (!sps->seq_scaling_matrix_present_flag) {
                    p_Vid->qmatrix[i] = Default4x4Inter;
                }
            } else {
                p_Vid->qmatrix[i] = p_Vid->qmatrix[i - 1];
            }
        } else {
            if (pps->UseDefaultScalingMatrix4x4Flag[i]) {
                p_Vid->qmatrix[i] = (i < 3) ? Default4x4Intra : Default4x4Inter;
            } else {
                p_Vid->qmatrix[i] = pps->ScalingList4x4[i];
            }
        }
    }
    for (i = 6; i < ((sps->chroma_format_idc != H264_CHROMA_444) ? 8 : 12); ++i) {
        if (!pps->pic_scaling_list_present_flag[i]) { // fall-back rule B
            if (i == 6) {
                if (!sps->seq_scaling_matrix_present_flag) {
                    p_Vid->qmatrix[i] = Default8x8Intra;
                }
            } else if (i == 7) {
                if (!sps->seq_scaling_matrix_present_flag)
                    p_Vid->qmatrix[i] = Default8x8Inter;
            } else
                p_Vid->qmatrix[i] = p_Vid->qmatrix[i - 2];
        } else {
            if (pps->UseDefaultScalingMatrix8x8Flag[i - 6]) {
                p_Vid->qmatrix[i] = (i == 6 || i == 8 || i == 10) ? Default8x8Intra : Default8x8Inter;
            } else {
                p_Vid->qmatrix[i] = pps->ScalingList8x8[i - 6];
            }
        }
    }
}

/*!
***********************************************************************
* \brief
*    check profile
***********************************************************************
*/
//extern "C"
RK_U32 is_prext_profile(RK_U32 profile_idc)
{
    return (profile_idc >= H264_PROFILE_HIGH || profile_idc == H264_PROFILE_FREXT_CAVLC444) ? 1 : 0;
}

/*!
***********************************************************************
* \brief
*    parse sps and process sps
***********************************************************************
*/
//extern "C"
MPP_RET parse_scalingList(BitReadCtx_t *p_bitctx, RK_S32 size, RK_S32 *scaling_list, RK_S32 *use_default)
{
    MPP_RET ret = MPP_ERR_UNKNOW;
    RK_S32 last_scale = 8;
    RK_S32 next_scale = 8;
    RK_S32 delta_scale = 0;
    RK_S32 j = 0, scanj = 0;

    RK_U8  *zz_scan = (size > 16) ? ZZ_SCAN8 : ZZ_SCAN;

    *use_default = 0;
    for (j = 0; j < size; ++j) {
        scanj = zz_scan[j];
        if (next_scale != 0) {
            READ_SE(p_bitctx, &delta_scale);
            next_scale = (last_scale + delta_scale + 256) & 0xff;
            *use_default = (scanj == 0 && next_scale == 0) ? 1 : 0;
        }
        scaling_list[scanj] = (next_scale == 0) ? last_scale : next_scale;
        last_scale = scaling_list[scanj];
    }

    return ret = MPP_OK;
__BITREAD_ERR:
    ret = p_bitctx->ret;
    return ret;
}


/*!
***********************************************************************
* \brief
*    parse sps and process sps
***********************************************************************
*/
//extern "C"
MPP_RET get_max_dec_frame_buf_size(H264_SPS_t *sps)
{
    RK_S32 size = 0;
    RK_S32 pic_size = 0;
    MPP_RET ret = MPP_ERR_UNKNOW;


    switch (sps->level_idc) {
    case 9:
        size = 152064;
        break;
    case 10:
        size = 152064;
        break;
    case 11:
        if (sps->constrained_set3_flag && !is_prext_profile(sps->profile_idc)) {
            size = 152064;
        } else {
            size = 345600;
        }
        break;
    case 12:
        size = 912384;
        break;
    case 13:
        size = 912384;
        break;
    case 20:
        size = 912384;
        break;
    case 21:
        size = 1824768;
        break;
    case 22:
        size = 3110400;
        break;
    case 30:
        size = 3110400;
        break;
    case 31:
        size = 6912000;
        break;
    case 32:
        size = 7864320;
        break;
    case 40:
        size = 12582912;
        break;
    case 41:
        size = 12582912;
        break;
    case 42:
        size = 13369344;
        break;
    case 50:
        size = 42393600;
        break;
    case 51:
        size = 70778880;
        break;
    case 52:
        size = 70778880;
        break;
    case 60:
        size = 267386880;
        break;
    case 61:
        size = 267386880;
        break;
    case 62:
        size = 267386880;
        break;
    default:
        ASSERT(0);  // undefined level
        return ret = MPP_NOK;
    }
    pic_size = (sps->pic_width_in_mbs_minus1 + 1)
               * (sps->pic_height_in_map_units_minus1 + 1)
               * (sps->frame_mbs_only_flag ? 1 : 2) * 384;
    size /= pic_size;
    size = MPP_MIN(size, 16);
    sps->max_dec_frame_buffering = size;

    return ret = MPP_OK;
}

/*!
***********************************************************************
* \brief
*    parse sps and process sps
***********************************************************************
*/
//extern "C"
MPP_RET parse_sps_scalinglists(BitReadCtx_t *p_bitctx, H264_SPS_t *sps)
{
    RK_S32 i = 0;
    MPP_RET ret = MPP_ERR_UNKNOW;
    // Parse scaling_list4x4.
    for (i = 0; i < 6; ++i) {
        READ_ONEBIT(p_bitctx, &sps->seq_scaling_list_present_flag[i]);

        if (sps->seq_scaling_list_present_flag[i]) {
            FUN_CHECK(ret = parse_scalingList(p_bitctx, H264ScalingList4x4Length,
                                              sps->ScalingList4x4[i], &sps->UseDefaultScalingMatrix4x4Flag[i]));
        }
    }
    // Parse scaling_list8x8.
    for (i = 0; i < ((sps->chroma_format_idc != H264_CHROMA_444) ? 2 : 6); ++i) {
        READ_ONEBIT(p_bitctx, &sps->seq_scaling_list_present_flag[6 + i]);
        if (sps->seq_scaling_list_present_flag[6 + i]) {
            FUN_CHECK(ret = parse_scalingList(p_bitctx, H264ScalingList8x8Length,
                                              sps->ScalingList8x8[i], &sps->UseDefaultScalingMatrix8x8Flag[i]));
        }
    }

    return ret = MPP_OK;
__BITREAD_ERR:
    ret = p_bitctx->ret;
__FAILED:
    return ret;
}
/*!
***********************************************************************
* \brief
*    prepare scanlist info to register syntax
***********************************************************************
*/
//extern "C"
MPP_RET prepare_init_scanlist(H264_SLICE_t *currSlice)
{
    RK_S32 i = 0;
    H264_SPS_t *sps = currSlice->p_Vid->active_sps;
    H264_PPS_t *pps = currSlice->p_Vid->active_pps;

    if (!pps->pic_scaling_matrix_present_flag && !sps->seq_scaling_matrix_present_flag) {
        for (i = 0; i < 12; i++) {
            currSlice->p_Vid->qmatrix[i] = (i < 6) ? Default4x4 : Default8x8;
        }
    } else {
        if (sps->seq_scaling_matrix_present_flag) { // check sps first
            set_sps_scanlist_matrix(sps, currSlice->p_Vid);
        }
        if (pps->pic_scaling_matrix_present_flag) { // then check pps
            set_pps_scanlist_matrix(sps, pps, currSlice->p_Vid);
        }
    }
    return MPP_OK;
}
