blob: 978f9b30bc32e0d3db4fe16675e39515e56e38c3 [file] [log] [blame]
/*
* Copyright (c) 2022 Samsung Electronics Co., Ltd.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the copyright owner, nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "oapv_def.h"
///////////////////////////////////////////////////////////////////////////////
// start of encoder code
#if ENABLE_ENCODER
///////////////////////////////////////////////////////////////////////////////
/* number of bytes to be sunk */
#define BSW_GET_SINK_BYTE(bs) ((32 - (bs)->leftbits + 7) >> 3)
static int bsw_flush(oapv_bs_t *bs, int bytes)
{
if(bytes == 0)
bytes = BSW_GET_SINK_BYTE(bs);
while(bytes--) {
*bs->cur++ = (bs->code >> 24) & 0xFF;
bs->code <<= 8;
}
bs->leftbits = 32;
return 0;
}
void oapv_bsw_init(oapv_bs_t *bs, u8 *buf, int size, oapv_bs_fn_flush_t fn_flush)
{
bs->size = size;
bs->beg = buf;
bs->cur = buf;
bs->end = buf + size - 1;
bs->code = 0;
bs->leftbits = 32;
bs->fn_flush = (fn_flush == NULL ? bsw_flush : fn_flush);
bs->is_bin_count = 0;
bs->bin_count = 0;
}
void oapv_bsw_deinit(oapv_bs_t *bs)
{
bs->fn_flush(bs, 0);
}
void *oapv_bsw_sink(oapv_bs_t *bs)
{
oapv_assert_rv(bs->cur + BSW_GET_SINK_BYTE(bs) <= bs->end, NULL);
bs->fn_flush(bs, 0);
bs->code = 0;
bs->leftbits = 32;
return (void *)bs->cur;
}
int oapv_bsw_write_direct(void *bits, u32 val, int len)
{
int i;
unsigned char *p = (unsigned char *)bits;
oapv_assert_rv((len & 0x7) == 0, -1); // len should be byte-aligned
val <<= (32 - len);
for(i = 0; i < (len >> 3); i++) {
p[i] = (val >> 24) & 0xFF;
val <<= 8;
}
return 0;
}
int oapv_bsw_write1(oapv_bs_t *bs, int val)
{
oapv_assert(bs);
if(bs->is_bin_count) {
bs->bin_count++;
return 0;
}
bs->leftbits--;
bs->code |= ((val & 0x1) << bs->leftbits);
if(bs->leftbits == 0) {
oapv_assert_rv(bs->cur <= bs->end, -1);
bs->fn_flush(bs, 0);
bs->code = 0;
bs->leftbits = 32;
}
return 0;
}
int oapv_bsw_write(oapv_bs_t *bs, u32 val, int len) /* len(1 ~ 32) */
{
int leftbits;
oapv_assert(bs);
if(bs->is_bin_count) {
bs->bin_count += len;
return 0;
}
leftbits = bs->leftbits;
val <<= (32 - len);
bs->code |= (val >> (32 - leftbits));
if(len < leftbits) {
bs->leftbits -= len;
}
else {
oapv_assert_rv(bs->cur + 4 <= bs->end, -1);
bs->leftbits = 0;
bs->fn_flush(bs, 0);
bs->code = (leftbits < 32 ? val << leftbits : 0);
bs->leftbits = 32 - (len - leftbits);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// end of encoder code
#endif // ENABLE_ENCODER
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// start of decoder code
#if ENABLE_DECODER
///////////////////////////////////////////////////////////////////////////////
/* Table of count of leading zero for 4 bit value */
static const u8 tbl_zero_count4[16] = {
4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
};
// skip code if lefbits are larger than skip bit count;
static void inline bsr_skip_code(oapv_bs_t *bs, int size)
{
oapv_assert(size <= 32);
oapv_assert(bs->leftbits >= size);
if(size == 32) {
bs->code = 0;
bs->leftbits = 0;
}
else {
bs->code <<= size;
bs->leftbits -= size;
}
}
static int bsr_flush(oapv_bs_t *bs, int byte)
{
int shift = 24, remained;
u32 code = 0;
oapv_assert(byte);
remained = (int)(bs->end - bs->cur) + 1;
if(byte > remained)
byte = remained;
if(byte <= 0) {
bs->code = 0;
bs->leftbits = 0;
return -1;
}
bs->leftbits = byte << 3;
while(byte) {
code |= *(bs->cur++) << shift;
byte--;
shift -= 8;
}
bs->code = code;
return 0;
}
void oapv_bsr_init(oapv_bs_t *bs, u8 *buf, u32 size, oapv_bs_fn_flush_t fn_flush)
{
bs->size = size;
bs->cur = buf;
bs->beg = buf;
bs->end = buf + size - 1;
bs->code = 0;
bs->leftbits = 0;
bs->fn_flush = (fn_flush == NULL) ? bsr_flush : fn_flush;
}
int oapv_bsr_clz_in_code(u32 code)
{
int clz, bits4, shift;
if(code == 0)
return 32; /* to protect infinite loop */
bits4 = 0;
clz = 0;
shift = 28;
while(bits4 == 0 && shift >= 0) {
bits4 = (code >> shift) & 0xf;
clz += tbl_zero_count4[bits4];
shift -= 4;
}
return clz;
}
int oapv_bsr_clz(oapv_bs_t *bs)
{
int clz;
u32 code;
code = oapv_bsr_peek(bs, 32);
oapv_assert(code != 0);
clz = oapv_bsr_clz_in_code(code);
return clz;
}
void oapv_bsr_align8(oapv_bs_t *bs)
{
/*
while (!bsr_is_align8(bs)) {
oapv_bsr_read1(bs);
}
*/
int size;
size = bs->leftbits & 0x7;
bs->code <<= size;
bs->leftbits -= size;
}
void oapv_bsr_skip(oapv_bs_t *bs, int size)
{
oapv_assert(size > 0 && size <= 32);
if(bs->leftbits < size) {
size -= bs->leftbits;
if(bs->fn_flush(bs, 4)) {
// oapv_trace("already reached the end of bitstream\n"); /* should be updated */
return;
}
}
bsr_skip_code(bs, size);
}
u32 oapv_bsr_peek(oapv_bs_t *bs, int size)
{
int byte, leftbits;
u32 code = 0;
if(bs->leftbits < size) {
byte = (32 - bs->leftbits) >> 3;
/* We should not check the return value
because this function could be failed at the EOB. */
if(byte) {
code = bs->code;
leftbits = bs->leftbits;
bs->fn_flush(bs, byte);
bs->code >>= leftbits;
bs->code |= code;
bs->leftbits += leftbits;
}
}
oapv_assert(bs->leftbits <= 32);
code = bs->code >> (32 - size);
size -= bs->leftbits;
if(size > 0) {
/* even though we update several bytes, the requested size would be
larger than current bs->leftbits.
In this case, we should read one more byte, but we could not store
the read byte. */
if(bs->cur <= bs->end) {
code |= *(bs->cur) >> (8 - size);
}
}
return code;
}
void *oapv_bsr_sink(oapv_bs_t *bs)
{
oapv_assert_rv(bs->cur + BSW_GET_SINK_BYTE(bs) <= bs->end, NULL);
oapv_assert_rv((bs->leftbits & 7) == 0, NULL);
bs->cur = bs->cur - (bs->leftbits >> 3);
bs->code = 0;
bs->leftbits = 0;
return (void *)bs->cur;
}
void oapv_bsr_move(oapv_bs_t *bs, u8 *pos)
{
bs->code = 0;
bs->leftbits = 0;
bs->cur = pos;
}
u32 oapv_bsr_read(oapv_bs_t *bs, int size)
{
u32 code = 0;
oapv_assert(size > 0);
if(bs->leftbits < size) {
code = bs->code >> (32 - size);
size -= bs->leftbits;
if(bs->fn_flush(bs, 4)) {
oapv_trace("already reached the end of bitstream\n"); /* should be updated */
return (u32)(-1);
}
}
code |= bs->code >> (32 - size);
bsr_skip_code(bs, size);
return code;
}
int oapv_bsr_read1(oapv_bs_t *bs)
{
int code;
if(bs->leftbits == 0) {
if(bs->fn_flush(bs, 4)) {
oapv_trace("already reached the end of bitstream\n"); /* should be updated */
return -1;
}
}
code = (int)(bs->code >> 31);
bs->code <<= 1;
bs->leftbits -= 1;
return code;
}
///////////////////////////////////////////////////////////////////////////////
// end of decoder code
#endif // ENABLE_DECODER
///////////////////////////////////////////////////////////////////////////////