/******************************************************************************
*
* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
*
* 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.
*
******************************************************************************/
/**
*******************************************************************************
* @file
* ihevcd_bitstream.c
*
* @brief
* Contains functions for bitstream access
*
* @author
* Harish
*
* @par List of Functions:
* - ihevcd_bits_init()
* - ihevcd_bits_flush()
* - ihevcd_bits_flush_to_byte_boundary()
* - ihevcd_bits_nxt()
* - ihevcd_bits_nxt32()
* - ihevcd_bits_get()
* - ihevcd_bits_num_bits_remaining()
* - ihevcd_bits_num_bits_consumed()
* - ihevcd_sev()
* - ihevcd_uev()
*
*
* @remarks
* None
*
*******************************************************************************
*/
/*****************************************************************************/
/* File Includes */
/*****************************************************************************/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "ihevc_typedefs.h"
#include "iv.h"
#include "ivd.h"
#include "ihevcd_cxa.h"
#include "ihevc_defs.h"
#include "ihevc_debug.h"
#include "ihevc_structs.h"
#include "ihevc_macros.h"
#include "ihevc_platform_macros.h"
#include "ihevc_cabac_tables.h"
#include "ihevcd_defs.h"
#include "ihevcd_function_selector.h"
#include "ihevcd_structs.h"
#include "ihevcd_error.h"
#include "ihevcd_bitstream.h"
/*****************************************************************************/
/* Function Prototypes */
/*****************************************************************************/
/**
*******************************************************************************
*
* @brief
* Function used for bitstream structure initialization
*
* @par Description:
* Initialize bitstream structure elements
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @param[in] pu1_buf
* Pointer to bitstream data
*
* @param[in] u4_numbytes
* Number of bytes in bitstream
*
* @returns none
*
* @remarks
* Assumes pu1_buf is aligned to 4 bytes. If not aligned then all bitstream
* accesses will be unaligned and hence costlier. Since this is codec memory
* that holds emulation prevented data, assumption of aligned to 4 bytes is
* valid
*
*******************************************************************************
*/
void ihevcd_bits_init(bitstrm_t *ps_bitstrm,
UWORD8 *pu1_buf,
UWORD32 u4_numbytes)
{
UWORD32 u4_cur_word;
UWORD32 u4_nxt_word;
UWORD32 u4_temp;
UWORD32 *pu4_buf;
pu4_buf = (UWORD32 *)pu1_buf;
u4_temp = *pu4_buf++;
u4_cur_word = ITT_BIG_ENDIAN(u4_temp);
u4_temp = *pu4_buf++;
u4_nxt_word = ITT_BIG_ENDIAN(u4_temp);
ps_bitstrm->u4_bit_ofst = 0;
ps_bitstrm->pu1_buf_base = pu1_buf;
ps_bitstrm->pu4_buf = pu4_buf;
ps_bitstrm->u4_cur_word = u4_cur_word;
ps_bitstrm->u4_nxt_word = u4_nxt_word;
ps_bitstrm->pu1_buf_max = pu1_buf + u4_numbytes + 8;
return;
}
/**
*******************************************************************************
*
* @brief
* Flushes given number of bits. Bits consumed increases by this number
*
* @par Description:
* Increment bit offset by numbits. If bit offset increases beyond 32, then
* move nxt_word to cur_word, read next word32 to nxt_word after endian
* conversion
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @param[in] u4_numbits
* Number of bits to be flushed
*
* @returns None
*
* @remarks
*
*
*******************************************************************************
*/
void ihevcd_bits_flush(bitstrm_t *ps_bitstrm, UWORD32 u4_numbits)
{
BITS_FLUSH(ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
u4_numbits);
return;
}
/**
*******************************************************************************
*
* @brief
* Flushes to next byte boundary.Bits consumed increases by this number
*
* @par Description:
* Compute number of bits remaining in the current byte then call
* ihevcd_bits_flush() bits with this number
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @returns None
*
* @remarks
*
*
*******************************************************************************
*/
void ihevcd_bits_flush_to_byte_boundary(bitstrm_t *ps_bitstrm)
{
UWORD32 u4_numbits;
u4_numbits = (ps_bitstrm->u4_bit_ofst) & 7;
u4_numbits = 8 - u4_numbits;
BITS_FLUSH(ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
u4_numbits);
return;
}
/**
*******************************************************************************
*
* @brief
* Seeks by given number of bits in the bitstream from current position
*
* @par Description:
* Add given number of bits to bitstream offset and update pu4_buf, cur_word and
* nxt_word accordingly
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @param[in] numbits
* Number of bits to seek
*
* @returns None
*
* @remarks
* Assumes emulation prevention has been done before and the buffer does not
* contain any emulation prevention bytes
*
*******************************************************************************
*/
void ihevcd_bits_seek(bitstrm_t *ps_bitstrm, WORD32 numbits)
{
WORD32 val;
ASSERT(numbits >= -32);
ASSERT(numbits <= 32);
/* Check if Seeking backwards*/
if(numbits < 0)
{
UWORD32 abs_numbits = -numbits;
if(ps_bitstrm->u4_bit_ofst >= abs_numbits)
{
/* If the current offset is greater than number of bits to seek back,
* then subtract abs_numbits from offset and return.
*/
ps_bitstrm->u4_bit_ofst -= abs_numbits;
return;
}
else
{
/* If the current offset is lesser than number of bits to seek back,
* then subtract abs_numbits from offset and add 32 and move cur_word to nxt_word
* and load cur_word appropriately and decrement pu4_buf
*/
ps_bitstrm->u4_bit_ofst += 32;
ps_bitstrm->u4_bit_ofst -= abs_numbits;
ps_bitstrm->pu4_buf--;
val = *(ps_bitstrm->pu4_buf - 2);
ps_bitstrm->u4_nxt_word = ps_bitstrm->u4_cur_word;
ps_bitstrm->u4_cur_word = ITT_BIG_ENDIAN(val);
return;
}
}
else
{
/* Not supported/tested currently */
ASSERT(1);
BITS_FLUSH(ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
numbits);
}
return;
}
/**
*******************************************************************************
*
* @brief
* Snoops for next numbits number of bits from the bitstream this does not
* update the bitstream offset and does not consume the bits
*
* @par Description:
* Extract required number of bits from cur_word & nxt_word return these
* bits
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @param[in] u4_numbits
* Number of bits
*
* @returns Next u4_numbits number of bits
*
* @remarks
*
*
*******************************************************************************
*/
UWORD32 ihevcd_bits_nxt(bitstrm_t *ps_bitstrm, UWORD32 u4_numbits)
{
UWORD32 u4_bits_read;
BITS_NXT(u4_bits_read,
ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
u4_numbits);
return u4_bits_read;
}
/**
*******************************************************************************
*
* @brief
* Snoops for next 32 bits from the bitstream this does not update the
* bitstream offset and does not consume the bits
*
* @par Description:
* Extract required number of bits from cur_word & nxt_word return these
* bits
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @param[in] u4_numbits
* Number of bits
*
* @returns Next 32 bits
*
* @remarks
*
*
*******************************************************************************
*/
UWORD32 ihevcd_bits_nxt32(bitstrm_t *ps_bitstrm, UWORD32 u4_numbits)
{
UWORD32 u4_bits_read;
UNUSED(u4_numbits);
BITS_NXT32(u4_bits_read,
ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word);
return u4_bits_read;
}
/**
*******************************************************************************
*
* @brief
* Reads next numbits number of bits from the bitstream this updates the
* bitstream offset and consumes the bits
*
* @par Description:
* Extract required number of bits from cur_word & nxt_word return these
* bits
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @param[in] u4_numbits
* Number of bits
*
* @returns Bits read
*
* @remarks
*
*
*******************************************************************************
*/
UWORD32 ihevcd_bits_get(bitstrm_t *ps_bitstrm, UWORD32 u4_numbits)
{
UWORD32 u4_bits_read;
BITS_GET(u4_bits_read,
ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
u4_numbits);
return u4_bits_read;
}
/**
*******************************************************************************
*
* @brief
* Returns the number of bits remaining in the bitstream
*
* @par Description:
* Compute number of bits remaining based on current pointer and buffer base
* and current offset. Since 8 bytes are read at the start into cur_word and
* nxt_word and are not consumed, 8 has to be subtracted
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @returns Total number of bits remaining
*
* @remarks
*
*
*******************************************************************************
*/
UWORD32 ihevcd_bits_num_bits_remaining(bitstrm_t *ps_bitstrm)
{
UWORD32 u4_bits_consumed;
UWORD32 u4_size_in_bits;
/* 8 bytes are read in cur_word and nxt_word at the start. Hence */
/* subtract 8 bytes */
u4_bits_consumed = (UWORD32)(((UWORD8 *)ps_bitstrm->pu4_buf -
(UWORD8 *)ps_bitstrm->pu1_buf_base - 8) <<
3) + ps_bitstrm->u4_bit_ofst;
u4_size_in_bits = (UWORD32)(ps_bitstrm->pu1_buf_max -
ps_bitstrm->pu1_buf_base) - 8;
u4_size_in_bits <<= 3;
if(u4_size_in_bits > u4_bits_consumed)
{
return (u4_size_in_bits - u4_bits_consumed);
}
else
{
return 0;
}
}
/**
*******************************************************************************
*
* @brief
* Returns the number of bits consumed in the bitstream
*
* @par Description:
* Compute number of bits consumed based on current pointer and buffer base
* and current offset. Since 8 bytes are read at the start into cur_word and
* nxt_word and are not consumed, 8 has to be subtracted
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @returns Total number of bits bits consumed
*
* @remarks
*
*
*******************************************************************************
*/
UWORD32 ihevcd_bits_num_bits_consumed(bitstrm_t *ps_bitstrm)
{
UWORD32 u4_bits_consumed;
/* 8 bytes are read in cur_word and nxt_word at the start. Hence */
/* subtract 8 bytes */
u4_bits_consumed = (UWORD32)(((UWORD8 *)ps_bitstrm->pu4_buf -
(UWORD8 *)ps_bitstrm->pu1_buf_base - 8) <<
3) + ps_bitstrm->u4_bit_ofst;
return u4_bits_consumed;
}
/**
*******************************************************************************
*
* @brief
* Reads unsigned integer 0-th order exp-golomb-coded syntax element from
* the bitstream Section: 9.2
*
* @par Description:
* Extract required number of bits from cur_word & nxt_word return these
* bits
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @returns UEV decoded syntax element
*
* @remarks
*
*
*******************************************************************************
*/
UWORD32 ihevcd_uev(bitstrm_t *ps_bitstrm)
{
UWORD32 u4_bits_read;
UWORD32 u4_clz;
/***************************************************************/
/* Find leading zeros in next 32 bits */
/***************************************************************/
BITS_NXT32(u4_bits_read,
ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word);
u4_clz = CLZ(u4_bits_read);
BITS_FLUSH(ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
(u4_clz + 1));
u4_bits_read = 0;
if(u4_clz)
{
BITS_GET(u4_bits_read,
ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
u4_clz);
}
return ((1 << u4_clz) + u4_bits_read - 1);
}
/**
*******************************************************************************
*
* @brief
* Reads signed integer 0-th order exp-golomb-coded syntax element from the
* bitstream. Function similar to get_uev Section: 9.2.1
*
* @par Description:
* Extract required number of bits from cur_word & nxt_word return these
* bits
*
* @param[in] ps_bitstrm
* Pointer to bitstream structure
*
* @returns UEV decoded syntax element
*
* @remarks
*
*
*******************************************************************************
*/
WORD32 ihevcd_sev(bitstrm_t *ps_bitstrm)
{
UWORD32 u4_bits_read;
UWORD32 u4_clz;
UWORD32 u4_abs_val;
/***************************************************************/
/* Find leading zeros in next 32 bits */
/***************************************************************/
BITS_NXT32(u4_bits_read,
ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word);
u4_clz = CLZ(u4_bits_read);
BITS_FLUSH(ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
(u4_clz + 1));
u4_bits_read = 0;
if(u4_clz)
{
BITS_GET(u4_bits_read,
ps_bitstrm->pu4_buf,
ps_bitstrm->u4_bit_ofst,
ps_bitstrm->u4_cur_word,
ps_bitstrm->u4_nxt_word,
u4_clz);
}
u4_abs_val = ((1 << u4_clz) + u4_bits_read) >> 1;
if(u4_bits_read & 0x1)
return (-(WORD32)u4_abs_val);
else
return (u4_abs_val);
}