You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
915 lines
30 KiB
915 lines
30 KiB
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* 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.
|
|
*
|
|
*****************************************************************************
|
|
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
|
|
*/
|
|
/**
|
|
******************************************************************************
|
|
* @file ihevce_cabac.c
|
|
*
|
|
* @brief
|
|
* This file contains function definitions related to bitstream generation
|
|
*
|
|
* @author
|
|
* ittiam
|
|
*
|
|
* @List of Functions
|
|
* ihevce_cabac_reset()
|
|
* ihevce_cabac_init()
|
|
* ihevce_cabac_put_byte()
|
|
* ihevce_cabac_encode_bin()
|
|
* ihevce_cabac_encode_bypass_bin()
|
|
* ihevce_cabac_encode_terminate()
|
|
* ihevce_cabac_encode_tunary()
|
|
* ihevce_cabac_encode_tunary_bypass()
|
|
* ihevce_cabac_encode_bypass_bins()
|
|
* ihevce_cabac_encode_egk()
|
|
* ihevce_cabac_encode_trunc_rice()
|
|
* ihevce_cabac_encode_trunc_rice_ctxt()
|
|
* ihevce_cabac_flush()
|
|
* ihevce_cabac_ctxt_backup()
|
|
* ihevce_cabac_ctxt_row_init()
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
|
|
/*****************************************************************************/
|
|
/* File Includes */
|
|
/*****************************************************************************/
|
|
/* System include files */
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <stdarg.h>
|
|
#include <math.h>
|
|
|
|
/* User include files */
|
|
#include "ihevc_typedefs.h"
|
|
#include "ihevc_debug.h"
|
|
#include "ihevc_macros.h"
|
|
#include "ihevc_platform_macros.h"
|
|
#include "ihevc_cabac_tables.h"
|
|
|
|
#include "ihevce_defs.h"
|
|
#include "ihevce_error_codes.h"
|
|
#include "ihevce_bitstream.h"
|
|
#include "ihevce_cabac.h"
|
|
|
|
#define TEST_CABAC_BITESTIMATE 0
|
|
|
|
/*****************************************************************************/
|
|
/* Function Definitions */
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Resets the encoder cabac engine
|
|
*
|
|
* @par Description
|
|
* This routine needs to be called at start of dependent slice encode
|
|
*
|
|
* @param[inout] ps_cabac_ctxt
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @param[in] ps_bitstrm
|
|
* pointer to bitstream context (handle)
|
|
*
|
|
* @param[in] e_cabac_op_mode
|
|
* opertaing mode of cabac; put bits / compute bits mode @sa CABAC_OP_MODE
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32
|
|
ihevce_cabac_reset(cab_ctxt_t *ps_cabac, bitstrm_t *ps_bitstrm, CABAC_OP_MODE e_cabac_op_mode)
|
|
{
|
|
/* Sanity checks */
|
|
ASSERT(ps_cabac != NULL);
|
|
ASSERT(
|
|
(e_cabac_op_mode == CABAC_MODE_ENCODE_BITS) ||
|
|
(e_cabac_op_mode == CABAC_MODE_COMPUTE_BITS));
|
|
|
|
ps_cabac->e_cabac_op_mode = e_cabac_op_mode;
|
|
|
|
if(CABAC_MODE_ENCODE_BITS == e_cabac_op_mode)
|
|
{
|
|
ASSERT(ps_bitstrm != NULL);
|
|
|
|
/* Bitstream context initialization */
|
|
ps_cabac->pu1_strm_buffer = ps_bitstrm->pu1_strm_buffer;
|
|
ps_cabac->u4_max_strm_size = ps_bitstrm->u4_max_strm_size;
|
|
/* When entropy sync is enabled start form fixed offset from point
|
|
* where slice header extension has ended to handle emulation prevention
|
|
* bytes during insertion of slice offset at end of frame */
|
|
if(1 == ps_cabac->i1_entropy_coding_sync_enabled_flag)
|
|
{
|
|
ps_cabac->u4_strm_buf_offset = ps_cabac->u4_first_slice_start_offset;
|
|
}
|
|
else
|
|
{
|
|
ps_cabac->u4_strm_buf_offset = ps_bitstrm->u4_strm_buf_offset;
|
|
}
|
|
ps_cabac->i4_zero_bytes_run = ps_bitstrm->i4_zero_bytes_run;
|
|
|
|
/* cabac engine initialization */
|
|
ps_cabac->u4_low = 0;
|
|
ps_cabac->u4_range = 510;
|
|
ps_cabac->u4_bits_gen = 0;
|
|
ps_cabac->u4_out_standing_bytes = 0;
|
|
}
|
|
else /* (CABAC_MODE_COMPUTE_BITS == e_cabac_op_mode) */
|
|
{
|
|
/* reset the bits estimated */
|
|
ps_cabac->u4_bits_estimated_q12 = 0;
|
|
|
|
/* reset the texture bits estimated */
|
|
ps_cabac->u4_texture_bits_estimated_q12 = 0;
|
|
|
|
/* Setting range to 0 switches off AEV_TRACE in compute bits mode */
|
|
ps_cabac->u4_range = 0;
|
|
}
|
|
|
|
return (IHEVCE_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Initializes the encoder cabac engine
|
|
*
|
|
* @par Description
|
|
* This routine needs to be called at start of slice/frame encode
|
|
*
|
|
* @param[inout] ps_cabac_ctxt
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @param[in] ps_bitstrm
|
|
* pointer to bitstream context (handle)
|
|
*
|
|
* @param[in] qp
|
|
* current slice qp
|
|
*
|
|
* @param[in] cabac_init_idc
|
|
* current slice init idc (range - [0- 2])*
|
|
*
|
|
* @param[in] e_cabac_op_mode
|
|
* opertaing mode of cabac; put bits / compute bits mode @sa CABAC_OP_MODE
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_init(
|
|
cab_ctxt_t *ps_cabac,
|
|
bitstrm_t *ps_bitstrm,
|
|
WORD32 slice_qp,
|
|
WORD32 cabac_init_idc,
|
|
CABAC_OP_MODE e_cabac_op_mode)
|
|
{
|
|
/* Sanity checks */
|
|
ASSERT(ps_cabac != NULL);
|
|
ASSERT((slice_qp >= 0) && (slice_qp < IHEVC_MAX_QP));
|
|
ASSERT((cabac_init_idc >= 0) && (cabac_init_idc < 3));
|
|
ASSERT(
|
|
(e_cabac_op_mode == CABAC_MODE_ENCODE_BITS) ||
|
|
(e_cabac_op_mode == CABAC_MODE_COMPUTE_BITS));
|
|
|
|
ps_cabac->e_cabac_op_mode = e_cabac_op_mode;
|
|
|
|
if(CABAC_MODE_ENCODE_BITS == e_cabac_op_mode)
|
|
{
|
|
ASSERT(ps_bitstrm != NULL);
|
|
|
|
/* Bitstream context initialization */
|
|
ps_cabac->pu1_strm_buffer = ps_bitstrm->pu1_strm_buffer;
|
|
ps_cabac->u4_max_strm_size = ps_bitstrm->u4_max_strm_size;
|
|
/* When entropy sync is enabled start form fixed offset from point
|
|
* where slice header extension has ended to handle emulation prevention
|
|
* bytes during insertion of slice offset at end of frame */
|
|
if(1 == ps_cabac->i1_entropy_coding_sync_enabled_flag)
|
|
{
|
|
ps_cabac->u4_strm_buf_offset = ps_cabac->u4_first_slice_start_offset;
|
|
}
|
|
else
|
|
{
|
|
ps_cabac->u4_strm_buf_offset = ps_bitstrm->u4_strm_buf_offset;
|
|
}
|
|
ps_cabac->i4_zero_bytes_run = ps_bitstrm->i4_zero_bytes_run;
|
|
|
|
/* cabac engine initialization */
|
|
ps_cabac->u4_low = 0;
|
|
ps_cabac->u4_range = 510;
|
|
ps_cabac->u4_bits_gen = 0;
|
|
ps_cabac->u4_out_standing_bytes = 0;
|
|
|
|
/* reset the bits estimated */
|
|
ps_cabac->u4_bits_estimated_q12 = 0;
|
|
|
|
/* reset the texture bits estimated */
|
|
ps_cabac->u4_texture_bits_estimated_q12 = 0;
|
|
}
|
|
else /* (CABAC_MODE_COMPUTE_BITS == e_cabac_op_mode) */
|
|
{
|
|
/* reset the bits estimated */
|
|
ps_cabac->u4_bits_estimated_q12 = 0;
|
|
|
|
/* reset the texture bits estimated */
|
|
ps_cabac->u4_texture_bits_estimated_q12 = 0;
|
|
|
|
/* Setting range to 0 switches off AEV_TRACE in compute bits mode */
|
|
ps_cabac->u4_range = 0;
|
|
}
|
|
|
|
/* cabac context initialization based on init idc and slice qp */
|
|
COPY_CABAC_STATES(
|
|
ps_cabac->au1_ctxt_models,
|
|
&gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0],
|
|
IHEVC_CAB_CTXT_END);
|
|
|
|
return (IHEVCE_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Puts new byte (and outstanding bytes) into bitstream after cabac
|
|
* renormalization
|
|
*
|
|
* @par Description
|
|
* 1. Extract the leading byte of low(L)
|
|
* 2. If leading byte=0xff increment outstanding bytes and return
|
|
* (as the actual bits depend on carry propogation later)
|
|
* 3. If leading byte is not 0xff check for any carry propogation
|
|
* 4. Insert the carry (propogated in previous byte) along with outstanding
|
|
* bytes (if any) and leading byte
|
|
*
|
|
*
|
|
* @param[inout] ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_put_byte(cab_ctxt_t *ps_cabac)
|
|
{
|
|
UWORD32 u4_low = ps_cabac->u4_low;
|
|
UWORD32 u4_bits_gen = ps_cabac->u4_bits_gen;
|
|
WORD32 lead_byte = u4_low >> (u4_bits_gen + CABAC_BITS - 8);
|
|
|
|
/* Sanity checks */
|
|
ASSERT((ps_cabac->u4_range >= 256) && (ps_cabac->u4_range < 512));
|
|
ASSERT((u4_bits_gen >= 8));
|
|
|
|
/* update bits generated and low after extracting leading byte */
|
|
u4_bits_gen -= 8;
|
|
ps_cabac->u4_low &= ((1 << (CABAC_BITS + u4_bits_gen)) - 1);
|
|
ps_cabac->u4_bits_gen = u4_bits_gen;
|
|
|
|
/************************************************************************/
|
|
/* 1. Extract the leading byte of low(L) */
|
|
/* 2. If leading byte=0xff increment outstanding bytes and return */
|
|
/* (as the actual bits depend on carry propogation later) */
|
|
/* 3. If leading byte is not 0xff check for any carry propogation */
|
|
/* 4. Insert the carry (propogated in previous byte) along with */
|
|
/* outstanding bytes (if any) and leading byte */
|
|
/************************************************************************/
|
|
if(lead_byte == 0xff)
|
|
{
|
|
/* actual bits depend on carry propogration */
|
|
ps_cabac->u4_out_standing_bytes++;
|
|
return (IHEVCE_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
/* carry = 1 => putbit(1); carry propogated due to L renorm */
|
|
WORD32 carry = (lead_byte >> 8) & 0x1;
|
|
UWORD8 *pu1_strm_buf = ps_cabac->pu1_strm_buffer;
|
|
UWORD32 u4_strm_buf_offset = ps_cabac->u4_strm_buf_offset;
|
|
WORD32 zero_run = ps_cabac->i4_zero_bytes_run;
|
|
UWORD32 u4_out_standing_bytes = ps_cabac->u4_out_standing_bytes;
|
|
|
|
/*********************************************************************/
|
|
/* Bitstream overflow check */
|
|
/* NOTE: corner case of epb bytes (max 2 for 32bit word) not handled */
|
|
/*********************************************************************/
|
|
if((u4_strm_buf_offset + u4_out_standing_bytes + 1) >= ps_cabac->u4_max_strm_size)
|
|
{
|
|
/* return without corrupting the buffer beyond its size */
|
|
return (IHEVCE_BITSTREAM_BUFFER_OVERFLOW);
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* Insert the carry propogated in previous byte */
|
|
/* */
|
|
/* Note : Do not worry about corruption into slice header align byte */
|
|
/* This is because the first bin cannot result in overflow */
|
|
/*********************************************************************/
|
|
if(carry)
|
|
{
|
|
/* CORNER CASE: if the previous data is 0x000003, then EPB will be inserted
|
|
and the data will become 0x00000303 and if the carry is present, it will
|
|
be added with the last byte and it will become 0x00000304 which is not correct
|
|
as per standard*/
|
|
/* so check for previous four bytes and if it is equal to 0x00000303
|
|
then subtract u4_strm_buf_offset by 1 */
|
|
if(pu1_strm_buf[u4_strm_buf_offset - 1] == 0x03 &&
|
|
pu1_strm_buf[u4_strm_buf_offset - 2] == 0x03 &&
|
|
pu1_strm_buf[u4_strm_buf_offset - 3] == 0x00 &&
|
|
pu1_strm_buf[u4_strm_buf_offset - 4] == 0x00)
|
|
{
|
|
u4_strm_buf_offset -= 1;
|
|
}
|
|
/* previous byte carry add will not result in overflow to */
|
|
/* u4_strm_buf_offset - 2 as we track 0xff as outstanding bytes */
|
|
pu1_strm_buf[u4_strm_buf_offset - 1] += carry;
|
|
zero_run = 0;
|
|
}
|
|
|
|
/* Insert outstanding bytes (if any) */
|
|
while(u4_out_standing_bytes)
|
|
{
|
|
UWORD8 u1_0_or_ff = carry ? 0 : 0xFF;
|
|
|
|
PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, u1_0_or_ff, zero_run);
|
|
|
|
u4_out_standing_bytes--;
|
|
}
|
|
ps_cabac->u4_out_standing_bytes = 0;
|
|
|
|
/* Insert the leading byte */
|
|
lead_byte &= 0xFF;
|
|
PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, lead_byte, zero_run);
|
|
|
|
/* update the state variables and return success */
|
|
ps_cabac->u4_strm_buf_offset = u4_strm_buf_offset;
|
|
ps_cabac->i4_zero_bytes_run = zero_run;
|
|
return (IHEVCE_SUCCESS);
|
|
}
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Codes a bypass bin (equi probable 0 / 1)
|
|
*
|
|
* @par Description
|
|
* After encoding bypass bin, bits gen incremented by 1 and bitstream generated
|
|
*
|
|
* @param[inout] ps_cabac : pointer to cabac context (handle)
|
|
*
|
|
* @param[in] bin : bypass bin(0/1) to be encoded
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_encode_bypass_bin(cab_ctxt_t *ps_cabac, WORD32 bin)
|
|
{
|
|
UWORD32 u4_range = ps_cabac->u4_range;
|
|
UWORD32 u4_low = ps_cabac->u4_low;
|
|
|
|
if(CABAC_MODE_ENCODE_BITS == ps_cabac->e_cabac_op_mode)
|
|
{
|
|
/* Sanity checks */
|
|
ASSERT((u4_range >= 256) && (u4_range < 512));
|
|
ASSERT((bin == 0) || (bin == 1));
|
|
|
|
/*Compute bit always to populate the trace*/
|
|
/* increment bits generated by 1 */
|
|
ps_cabac->u4_bits_estimated_q12 += (1 << CABAC_FRAC_BITS_Q);
|
|
|
|
u4_low <<= 1;
|
|
/* add range if bin is 1 */
|
|
if(bin)
|
|
{
|
|
u4_low += u4_range;
|
|
}
|
|
|
|
/* 1 bit to be inserted in the bitstream */
|
|
ps_cabac->u4_bits_gen++;
|
|
ps_cabac->u4_low = u4_low;
|
|
|
|
/* generate stream when a byte is ready */
|
|
if(ps_cabac->u4_bits_gen > CABAC_BITS)
|
|
{
|
|
return (ihevce_cabac_put_byte(ps_cabac));
|
|
}
|
|
}
|
|
else /* (CABAC_MODE_COMPUTE_BITS == e_cabac_op_mode) */
|
|
{
|
|
/* increment bits generated by 1 */
|
|
ps_cabac->u4_bits_estimated_q12 += (1 << CABAC_FRAC_BITS_Q);
|
|
}
|
|
|
|
return (IHEVCE_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Codes a terminate bin (1:terminate 0:do not terminate)
|
|
*
|
|
* @par Description
|
|
* After encoding bypass bin, bits gen incremented by 1 and bitstream generated
|
|
*
|
|
* @param[inout] ps_cabac : pointer to cabac context (handle)
|
|
*
|
|
* @param[in] term_bin : (1:terminate 0:do not terminate)
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32
|
|
ihevce_cabac_encode_terminate(cab_ctxt_t *ps_cabac, WORD32 term_bin, WORD32 i4_end_of_sub_strm)
|
|
{
|
|
UWORD32 u4_range = ps_cabac->u4_range;
|
|
UWORD32 u4_low = ps_cabac->u4_low;
|
|
UWORD32 u4_rlps;
|
|
WORD32 shift;
|
|
WORD32 error = IHEVCE_SUCCESS;
|
|
|
|
/* Sanity checks */
|
|
ASSERT((u4_range >= 256) && (u4_range < 512));
|
|
ASSERT((term_bin == 0) || (term_bin == 1));
|
|
|
|
/* term_bin = 1 has lps range = 2 */
|
|
u4_rlps = 2;
|
|
u4_range -= u4_rlps;
|
|
|
|
/* if terminate L is incremented by curR and R=2 */
|
|
if(term_bin)
|
|
{
|
|
/* lps path; L= L + R; R = RLPS */
|
|
u4_low += u4_range;
|
|
u4_range = u4_rlps;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
/* Renormalization; calculate bits generated based on range(R) */
|
|
/* Note : 6 <= R < 512; R is 2 only for terminating encode */
|
|
/*****************************************************************/
|
|
GETRANGE(shift, u4_range);
|
|
shift = 9 - shift;
|
|
u4_low <<= shift;
|
|
u4_range <<= shift;
|
|
|
|
/* bits to be inserted in the bitstream */
|
|
ps_cabac->u4_bits_gen += shift;
|
|
ps_cabac->u4_range = u4_range;
|
|
ps_cabac->u4_low = u4_low;
|
|
|
|
/* generate stream when a byte is ready */
|
|
if(ps_cabac->u4_bits_gen > CABAC_BITS)
|
|
{
|
|
error = ihevce_cabac_put_byte(ps_cabac);
|
|
}
|
|
|
|
if(term_bin)
|
|
{
|
|
ihevce_cabac_flush(ps_cabac, i4_end_of_sub_strm);
|
|
}
|
|
|
|
/*Compute bit always to populate the trace*/
|
|
ps_cabac->u4_bits_estimated_q12 += gau2_ihevce_cabac_bin_to_bits[(62 << 1) | term_bin];
|
|
|
|
return (error);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Encodes a truncated unary symbol associated with context model(s)
|
|
*
|
|
* @par Description
|
|
* Does binarization of tunary symbol as per sec 9.3.2.2 and does the cabac
|
|
* encoding of each bin. This is used for computing symbols like qp_delta,
|
|
* last_sig_coeff_prefix_x, last_sig_coeff_prefix_y.
|
|
*
|
|
* The context models associated with each bin is computed as :
|
|
* current bin context = "base context idx" + (bin_idx >> shift)
|
|
* where
|
|
* 1. "base context idx" is the base index for the syntax element
|
|
* 2. "bin_idx" is the current bin index of the unary code
|
|
* 3. "shift" is the shift factor associated with this syntax element
|
|
*
|
|
* @param[inout]ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @param[in] sym
|
|
* syntax element to be coded as truncated unary bins
|
|
*
|
|
* @param[in] c_max
|
|
* maximum value of sym (required for tunary binarization)
|
|
*
|
|
* @param[in] ctxt_index
|
|
* base context model index for this syntax element
|
|
*
|
|
* @param[in] ctxt_shift
|
|
* shift factor for context increments associated with this syntax element
|
|
*
|
|
* @param[in] ctxt_inc_max
|
|
* max value of context increment beyond which all bins will use same ctxt
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_encode_tunary(
|
|
cab_ctxt_t *ps_cabac,
|
|
WORD32 sym,
|
|
WORD32 c_max,
|
|
WORD32 ctxt_index,
|
|
WORD32 ctxt_shift,
|
|
WORD32 ctxt_inc_max)
|
|
{
|
|
WORD32 bin_ctxt, i;
|
|
WORD32 error = IHEVCE_SUCCESS;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(c_max > 0);
|
|
ASSERT((sym <= c_max) && (sym >= 0));
|
|
ASSERT((ctxt_index >= 0) && (ctxt_index < IHEVC_CAB_CTXT_END));
|
|
ASSERT((ctxt_index + (c_max >> ctxt_shift)) < IHEVC_CAB_CTXT_END);
|
|
|
|
/* Special case of sym= 0 */
|
|
if(0 == sym)
|
|
{
|
|
return (ihevce_cabac_encode_bin(ps_cabac, 0, ctxt_index));
|
|
}
|
|
|
|
/* write '1' bins */
|
|
for(i = 0; i < sym; i++)
|
|
{
|
|
/* TODO: encode bin to be inlined later */
|
|
bin_ctxt = ctxt_index + MIN((i >> ctxt_shift), ctxt_inc_max);
|
|
error |= ihevce_cabac_encode_bin(ps_cabac, 1, bin_ctxt);
|
|
}
|
|
|
|
/* write terminating 0 bin */
|
|
if(sym < c_max)
|
|
{
|
|
/* TODO: encode bin to be inlined later */
|
|
bin_ctxt = ctxt_index + MIN((i >> ctxt_shift), ctxt_inc_max);
|
|
error |= ihevce_cabac_encode_bin(ps_cabac, 0, bin_ctxt);
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Encodes a syntax element as truncated unary bypass bins
|
|
*
|
|
* @par Description
|
|
* Does binarization of tunary symbol as per sec 9.3.2.2 and does the cabac
|
|
* encoding of each bin. This is used for computing symbols like merge_idx,
|
|
* mpm_idx etc
|
|
*
|
|
* @param[inout]ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @param[in] sym
|
|
* syntax element to be coded as truncated unary bins
|
|
*
|
|
* @param[in] c_max
|
|
* maximum value of sym (required for tunary binarization)
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_encode_tunary_bypass(cab_ctxt_t *ps_cabac, WORD32 sym, WORD32 c_max)
|
|
{
|
|
WORD32 error = IHEVCE_SUCCESS;
|
|
WORD32 length;
|
|
WORD32 u4_bins;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(c_max > 0);
|
|
ASSERT((sym <= c_max) && (sym >= 0));
|
|
|
|
if(sym < c_max)
|
|
{
|
|
/* unary code with (sym) '1's and terminating '0' bin */
|
|
length = (sym + 1);
|
|
u4_bins = (1 << length) - 2;
|
|
}
|
|
else
|
|
{
|
|
/* tunary code with (sym) '1's */
|
|
length = sym;
|
|
u4_bins = (1 << length) - 1;
|
|
}
|
|
|
|
/* Encode the tunary binarized code as bypass bins */
|
|
error = ihevce_cabac_encode_bypass_bins(ps_cabac, u4_bins, length);
|
|
|
|
return (error);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Encodes a syntax element as kth order Exp-Golomb code (EGK)
|
|
*
|
|
* @par Description
|
|
* Does binarization of symbol as per sec 9.3.2.4 kth order Exp-Golomb(EGk)
|
|
* process and encodes the resulting bypass bins
|
|
*
|
|
* @param[inout]ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @param[in] u4_sym
|
|
* syntax element to be coded as EGK
|
|
*
|
|
* @param[in] k
|
|
* order of EGk
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_encode_egk(cab_ctxt_t *ps_cabac, UWORD32 u4_sym, WORD32 k)
|
|
{
|
|
WORD32 num_bins, unary_length;
|
|
UWORD32 u4_sym_shiftk_plus1, u4_egk, u4_unary_bins;
|
|
|
|
WORD32 error = IHEVCE_SUCCESS;
|
|
|
|
/* Sanity checks */
|
|
ASSERT((k >= 0));
|
|
/* ASSERT(u4_sym >= (UWORD32)(1 << k)); */
|
|
|
|
/************************************************************************/
|
|
/* shift symbol by k bits to find unary code prefix (111110) */
|
|
/* Use GETRANGE to elminate the while loop in sec 9.3.2.4 of HEVC spec */
|
|
/************************************************************************/
|
|
u4_sym_shiftk_plus1 = (u4_sym >> k) + 1;
|
|
/* GETRANGE(unary_length, (u4_sym_shiftk_plus1 + 1)); */
|
|
GETRANGE(unary_length, u4_sym_shiftk_plus1);
|
|
|
|
/* unary code with (unary_length-1) '1's and terminating '0' bin */
|
|
u4_unary_bins = (1 << unary_length) - 2;
|
|
|
|
/* insert the symbol prefix of (unary lenght - 1) bins */
|
|
u4_egk = (u4_unary_bins << (unary_length - 1)) |
|
|
(u4_sym_shiftk_plus1 & ((1 << (unary_length - 1)) - 1));
|
|
|
|
/* insert last k bits of symbol in the end */
|
|
u4_egk = (u4_egk << k) | (u4_sym & ((1 << k) - 1));
|
|
|
|
/* length of the code = 2 *(unary_length - 1) + 1 + k */
|
|
num_bins = (2 * unary_length) - 1 + k;
|
|
|
|
/* Encode the egk binarized code as bypass bins */
|
|
error = ihevce_cabac_encode_bypass_bins(ps_cabac, u4_egk, num_bins);
|
|
|
|
return (error);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Encodes a syntax element as truncated rice code (TR)
|
|
*
|
|
* @par Description
|
|
* Does binarization of symbol as per sec 9.3.2.3 Truncated Rice(TR)
|
|
* binarization process and encodes the resulting bypass bins
|
|
* This function ise used for coeff_abs_level_remaining coding when
|
|
* level is less than c_rice_max
|
|
*
|
|
* @param[inout]ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @param[in] u4_sym
|
|
* syntax element to be coded as truncated rice code
|
|
*
|
|
* @param[in] c_rice_param
|
|
* shift factor for truncated unary prefix coding of (u4_sym >> c_rice_param)
|
|
*
|
|
* @param[in] c_rice_max
|
|
* max symbol val below which a suffix is coded as (u4_sym%(1<<c_rice_param))
|
|
* This is currently (4 << c_rice_param) for coeff_abs_level_remaining
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_encode_trunc_rice(
|
|
cab_ctxt_t *ps_cabac, UWORD32 u4_sym, WORD32 c_rice_param, WORD32 c_rice_max)
|
|
{
|
|
WORD32 num_bins, unary_length, u4_unary_bins;
|
|
UWORD32 u4_tr;
|
|
|
|
WORD32 error = IHEVCE_SUCCESS;
|
|
|
|
(void)c_rice_max;
|
|
/* Sanity checks */
|
|
ASSERT((c_rice_param >= 0));
|
|
ASSERT((UWORD32)c_rice_max > u4_sym);
|
|
|
|
/************************************************************************/
|
|
/* shift symbol by c_rice_param bits to find unary code prefix (111.10) */
|
|
/************************************************************************/
|
|
unary_length = (u4_sym >> c_rice_param) + 1;
|
|
|
|
/* unary code with (unary_length-1) '1's and terminating '0' bin */
|
|
u4_unary_bins = (1 << unary_length) - 2;
|
|
|
|
/* insert last c_rice_param bits of symbol in the end */
|
|
u4_tr = (u4_unary_bins << c_rice_param) | (u4_sym & ((1 << c_rice_param) - 1));
|
|
|
|
/* length of the code */
|
|
num_bins = unary_length + c_rice_param;
|
|
|
|
/* Encode the tr binarized code as bypass bins */
|
|
error = ihevce_cabac_encode_bypass_bins(ps_cabac, u4_tr, num_bins);
|
|
|
|
return (error);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Flushes the cabac encoder engine as per section 9.3.4 figure 9-12
|
|
*
|
|
* @par Description
|
|
*
|
|
*
|
|
* @param[inout] ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_flush(cab_ctxt_t *ps_cabac, WORD32 i4_end_of_sub_strm)
|
|
{
|
|
UWORD32 u4_low = ps_cabac->u4_low;
|
|
UWORD32 u4_bits_gen = ps_cabac->u4_bits_gen;
|
|
|
|
UWORD8 *pu1_strm_buf = ps_cabac->pu1_strm_buffer;
|
|
UWORD32 u4_strm_buf_offset = ps_cabac->u4_strm_buf_offset;
|
|
WORD32 zero_run = ps_cabac->i4_zero_bytes_run;
|
|
UWORD32 u4_out_standing_bytes = ps_cabac->u4_out_standing_bytes;
|
|
|
|
(void)i4_end_of_sub_strm;
|
|
/************************************************************************/
|
|
/* Insert the carry (propogated in previous byte) along with */
|
|
/* outstanding bytes (if any) and flush remaining bits */
|
|
/************************************************************************/
|
|
|
|
//TODO: Review this function
|
|
{
|
|
/* carry = 1 => putbit(1); carry propogated due to L renorm */
|
|
WORD32 carry = (u4_low >> (u4_bits_gen + CABAC_BITS)) & 0x1;
|
|
WORD32 last_byte;
|
|
WORD32 bits_left;
|
|
WORD32 rem_bits;
|
|
|
|
/*********************************************************************/
|
|
/* Bitstream overflow check */
|
|
/* NOTE: corner case of epb bytes (max 2 for 32bit word) not handled */
|
|
/*********************************************************************/
|
|
if((u4_strm_buf_offset + u4_out_standing_bytes + 1) >= ps_cabac->u4_max_strm_size)
|
|
{
|
|
/* return without corrupting the buffer beyond its size */
|
|
return (IHEVCE_BITSTREAM_BUFFER_OVERFLOW);
|
|
}
|
|
|
|
if(carry)
|
|
{
|
|
/* CORNER CASE: if the previous data is 0x000003, then EPB will be inserted
|
|
and the data will become 0x00000303 and if the carry is present, it will
|
|
be added with the last byte and it will become 0x00000304 which is not correct
|
|
as per standard*/
|
|
/* so check for previous four bytes and if it is equal to 0x00000303
|
|
then subtract u4_strm_buf_offset by 1 */
|
|
if(pu1_strm_buf[u4_strm_buf_offset - 1] == 0x03 &&
|
|
pu1_strm_buf[u4_strm_buf_offset - 2] == 0x03 &&
|
|
pu1_strm_buf[u4_strm_buf_offset - 3] == 0x00 &&
|
|
pu1_strm_buf[u4_strm_buf_offset - 4] == 0x00)
|
|
{
|
|
u4_strm_buf_offset -= 1;
|
|
}
|
|
/* previous byte carry add will not result in overflow to */
|
|
/* u4_strm_buf_offset - 2 as we track 0xff as outstanding bytes */
|
|
pu1_strm_buf[u4_strm_buf_offset - 1] += carry;
|
|
zero_run = 0;
|
|
}
|
|
|
|
/* Insert outstanding bytes (if any) */
|
|
while(u4_out_standing_bytes)
|
|
{
|
|
UWORD8 u1_0_or_ff = carry ? 0 : 0xFF;
|
|
|
|
PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, u1_0_or_ff, zero_run);
|
|
|
|
u4_out_standing_bytes--;
|
|
}
|
|
|
|
/* clear the carry in low */
|
|
u4_low &= ((1 << (u4_bits_gen + CABAC_BITS)) - 1);
|
|
|
|
/* extract the remaining bits; */
|
|
/* includes additional msb bit of low as per Figure 9-12 */
|
|
bits_left = u4_bits_gen + 1;
|
|
rem_bits = (u4_low >> (u4_bits_gen + CABAC_BITS - bits_left));
|
|
|
|
if(bits_left >= 8)
|
|
{
|
|
last_byte = (rem_bits >> (bits_left - 8)) & 0xFF;
|
|
PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, last_byte, zero_run);
|
|
bits_left -= 8;
|
|
}
|
|
|
|
/* insert last byte along with rbsp stop bit(1) and 0's in the end */
|
|
last_byte = (rem_bits << (8 - bits_left)) | (1 << (7 - bits_left));
|
|
last_byte &= 0xFF;
|
|
PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, last_byte, zero_run);
|
|
|
|
/* update the state variables and return success */
|
|
ps_cabac->u4_strm_buf_offset = u4_strm_buf_offset;
|
|
ps_cabac->i4_zero_bytes_run = 0;
|
|
return (IHEVCE_SUCCESS);
|
|
}
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief API to backup cabac ctxt at end of 2nd CTB row which is used to init
|
|
* context at start of every row
|
|
*
|
|
* @par Description
|
|
* API to backup cabac ctxt at end of 2nd CTB row which is used to init
|
|
* context at start of every row
|
|
*
|
|
* @param[inout] ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_ctxt_backup(cab_ctxt_t *ps_cabac)
|
|
{
|
|
memcpy(
|
|
ps_cabac->au1_ctxt_models_top_right,
|
|
ps_cabac->au1_ctxt_models,
|
|
sizeof(ps_cabac->au1_ctxt_models));
|
|
return (IHEVCE_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* @brief Init cabac ctxt at every row start
|
|
*
|
|
* @par Description
|
|
* API to init cabac ctxt at start of every row when entropy sync is
|
|
* enabled
|
|
*
|
|
* @param[inout] ps_cabac
|
|
* pointer to cabac context (handle)
|
|
*
|
|
* @return success or failure error code
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
WORD32 ihevce_cabac_ctxt_row_init(cab_ctxt_t *ps_cabac)
|
|
{
|
|
/* cabac engine initialization */
|
|
ps_cabac->u4_low = 0;
|
|
ps_cabac->u4_range = 510;
|
|
ps_cabac->u4_bits_gen = 0;
|
|
ps_cabac->u4_out_standing_bytes = 0;
|
|
ps_cabac->i4_zero_bytes_run = 0;
|
|
|
|
/*copy top right context as init context when starting to encode a row*/
|
|
COPY_CABAC_STATES(
|
|
ps_cabac->au1_ctxt_models, ps_cabac->au1_ctxt_models_top_right, IHEVC_CAB_CTXT_END);
|
|
|
|
return (IHEVCE_SUCCESS);
|
|
}
|