[mpp_base] Add base bit writer function

This bitwrite function is for H.264/H.265 bit writing.

Change-Id: I98c0e50f51b8ab29ec630474a2bdf25d0553b7b5
Signed-off-by: sayon.chen <sayon.chen@rock-chips.com>
This commit is contained in:
sayon.chen 2019-10-14 15:32:13 +08:00 committed by Herman Chen
parent 042696c255
commit 53997e5cd8
5 changed files with 433 additions and 0 deletions

View file

@ -12,6 +12,7 @@ add_library(mpp_base STATIC
mpp_task_impl.cpp
mpp_task.cpp
mpp_meta.cpp
mpp_bitwrite.c
mpp_bitread.c
mpp_bitput.c
)

View file

@ -0,0 +1,67 @@
/*
* Copyright 2015 - 2017 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.
*/
#ifndef __MPP_BITWRITER_H__
#define __MPP_BITWRITER_H__
#include "rk_type.h"
#include "mpp_err.h"
/*
* Mpp bitstream writer for H.264/H.265
*/
typedef struct MppWriteCtx_t {
RK_U8 *buffer; /* point to first byte of stream */
RK_U8 *stream; /* Pointer to next byte of stream */
RK_U32 size; /* Byte size of stream buffer */
RK_U32 byte_cnt; /* Byte counter */
RK_U32 byte_buffer; /* Byte buffer */
RK_U32 buffered_bits; /* Amount of bits in byte buffer, [0-7] */
RK_U32 zero_bytes; /* Amount of consecutive zero bytes */
RK_S32 overflow; /* This will signal a buffer overflow */
RK_U32 emul_cnt; /* Counter for emulation_3_byte, needed in SEI */
} MppWriteCtx;
MPP_RET mpp_writer_init(MppWriteCtx *ctx, void *p, RK_S32 size);
MPP_RET mpp_writer_reset(MppWriteCtx *ctx);
/* check overflow status */
MPP_RET mpp_writer_status(MppWriteCtx *ctx);
/* write raw bit without emulation prevention 0x03 byte */
void mpp_writer_put_raw_bits(MppWriteCtx *ctx, RK_S32 val, RK_S32 len);
/* write bit with emulation prevention 0x03 byte */
void mpp_writer_put_bits(MppWriteCtx *ctx, RK_S32 val, RK_S32 len);
/* insert zero bits until byte-aligned */
void mpp_writer_align_zero(MppWriteCtx *ctx);
/* insert one bits until byte-aligned */
void mpp_writer_align_one(MppWriteCtx *ctx);
/* insert one bit then pad to byte-align with zero */
void mpp_writer_trailing(MppWriteCtx * ctx);
void mpp_writer_put_ue(MppWriteCtx *ctx, RK_U32 val);
void mpp_writer_put_se(MppWriteCtx *ctx, RK_S32 val);
RK_S32 mpp_writer_bytes(MppWriteCtx *ctx);
RK_S32 mpp_writer_bits(MppWriteCtx *ctx);
RK_S32 mpp_exp_golomb_signed(RK_S32 val);
#endif /* __MPP_BITWRITER_H__ */

235
mpp/base/mpp_bitwrite.c Normal file
View file

@ -0,0 +1,235 @@
/*
* Copyright 2015 - 2017 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 "mpp_log.h"
#include "mpp_mem.h"
#include "mpp_bitwrite.h"
MPP_RET mpp_writer_status(MppWriteCtx *ctx)
{
if (ctx->byte_cnt > ctx->size) {
ctx->overflow = 1;
return MPP_NOK;
}
return MPP_OK;
}
MPP_RET mpp_writer_reset(MppWriteCtx *ctx)
{
ctx->stream = ctx->buffer;
ctx->byte_cnt = 0;
ctx->byte_buffer = 0;
ctx->buffered_bits = 0;
ctx->zero_bytes = 0;
ctx->overflow = 0;
ctx->emul_cnt = 0;
return MPP_OK;
}
MPP_RET mpp_writer_init(MppWriteCtx *ctx, void *p, RK_S32 size)
{
MPP_RET ret;
ctx->buffer = p;
ctx->stream = p;
ctx->size = size;
ctx->byte_cnt = 0;
ctx->overflow = 0;
ctx->byte_buffer = 0;
ctx->buffered_bits = 0;
ctx->zero_bytes = 0;
ctx->emul_cnt = 0;
ret = mpp_writer_status(ctx);
if (ret)
mpp_err_f("failed to init with overflow config\n");
return ret;
}
void mpp_writer_put_raw_bits(MppWriteCtx *ctx, RK_S32 val, RK_S32 len)
{
RK_S32 bits;
RK_U32 byte_buffer = ctx->byte_buffer;
RK_U8*stream = ctx->stream;
if (mpp_writer_status(ctx))
return;
mpp_assert(val < (1 << len));
mpp_assert(len < 25);
bits = len + ctx->buffered_bits;
val <<= (32 - bits);
byte_buffer = byte_buffer | val;
while (bits > 7) {
*stream = (RK_U8)(byte_buffer >> 24);
bits -= 8;
byte_buffer <<= 8;
stream++;
ctx->byte_cnt++;
}
ctx->byte_buffer = byte_buffer;
ctx->buffered_bits = (RK_U8)bits;
ctx->stream = stream;
return;
}
void mpp_writer_put_bits(MppWriteCtx * ctx, RK_S32 val, RK_S32 len)
{
RK_S32 bits;
RK_U8 *stream = ctx->stream;
RK_U32 byte_buffer = ctx->byte_buffer;
if (val) {
mpp_assert(val < (1 << len));
mpp_assert(len < 25);
}
bits = len + ctx->buffered_bits;
byte_buffer = byte_buffer | ((RK_U32) val << (32 - bits));
while (bits > 7) {
RK_S32 zeroBytes = ctx->zero_bytes;
RK_S32 byteCnt = ctx->byte_cnt;
if (mpp_writer_status(ctx))
return;
*stream = (RK_U8) (byte_buffer >> 24);
byteCnt++;
if ((zeroBytes == 2) && (*stream < 4)) {
*stream++ = 3;
*stream = (RK_U8) (byte_buffer >> 24);
byteCnt++;
zeroBytes = 0;
ctx->emul_cnt++;
}
if (*stream == 0)
zeroBytes++;
else
zeroBytes = 0;
bits -= 8;
byte_buffer <<= 8;
stream++;
ctx->zero_bytes = zeroBytes;
ctx->byte_cnt = byteCnt;
ctx->stream = stream;
}
ctx->buffered_bits = (RK_U8) bits;
ctx->byte_buffer = byte_buffer;
}
void mpp_writer_align_zero(MppWriteCtx *ctx)
{
if (ctx->buffered_bits)
mpp_writer_put_raw_bits(ctx, 0, 8 - ctx->buffered_bits);
}
void mpp_writer_align_one(MppWriteCtx *ctx)
{
if (ctx->buffered_bits) {
RK_S32 len = 8 - ctx->buffered_bits;
mpp_writer_put_raw_bits(ctx, (1 << len) - 1, len);
}
}
void mpp_writer_trailing(MppWriteCtx *ctx)
{
mpp_writer_put_bits(ctx, 1, 1);
if (ctx->buffered_bits)
mpp_writer_put_bits(ctx, 0, 8 - ctx->buffered_bits);
}
void mpp_writer_put_ue(MppWriteCtx *ctx, RK_U32 val)
{
RK_U32 num_bits = 0;
val++;
while (val >> ++num_bits);
if (num_bits > 12) {
RK_U32 tmp;
tmp = num_bits - 1;
if (tmp > 24) {
tmp -= 24;
mpp_writer_put_bits(ctx, 0, 24);
}
mpp_writer_put_bits(ctx, 0, tmp);
if (num_bits > 24) {
num_bits -= 24;
mpp_writer_put_bits(ctx, val >> num_bits, 24);
val = val >> num_bits;
}
mpp_writer_put_bits(ctx, val, num_bits);
} else {
mpp_writer_put_bits(ctx, val, 2 * num_bits - 1);
}
}
void mpp_writer_put_se(MppWriteCtx *ctx, RK_S32 val)
{
RK_U32 tmp;
if (val > 0)
tmp = (RK_U32)(2 * val - 1);
else
tmp = (RK_U32)(-2 * val);
mpp_writer_put_ue(ctx, tmp);
}
RK_S32 mpp_writer_bytes(MppWriteCtx *ctx)
{
return ctx->byte_cnt + (ctx->buffered_bits > 0);
}
RK_S32 mpp_writer_bits(MppWriteCtx *ctx)
{
return ctx->byte_cnt * 8 + ctx->buffered_bits;
}
RK_S32 mpp_exp_golomb_signed(RK_S32 val)
{
RK_S32 tmp = 0;
if (val > 0)
val = 2 * val;
else
val = -2 * val + 1;
while (val >> ++tmp)
;
return tmp * 2 - 1;
}

View file

@ -28,3 +28,5 @@ add_mpp_base_test(mpp_buffer)
# mpp_packet unit test
add_mpp_base_test(mpp_packet)
# mpp_bitwriter unit test
add_mpp_base_test(mpp_bit)

View file

@ -0,0 +1,128 @@
/*
* 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.
*/
#define MODULE_TAG "mpp_bit_test"
#include <stdlib.h>
#include "mpp_log.h"
#include "mpp_common.h"
#include "mpp_bitwrite.h"
#define BIT_WRITER_BUFFER_SIZE 1024
/*
* type is for operation type
* 0 - plain bit put
* 1 - bit put with detection
* 2 - write ue
* 3 - write se
* 4 - align byte
*/
typedef enum BitOpsType_e {
BIT_PUT_NO03,
BIT_PUT,
BIT_PUT_UE,
BIT_PUT_SE,
BIT_ALIGN_BYTE,
} BitOpsType;
typedef struct BitOps_t {
BitOpsType type;
RK_S32 val;
RK_S32 len;
} BitOps;
static BitOps bit_ops[] = {
{ BIT_PUT_NO03, 0, 8, },
{ BIT_PUT, 0, 3, },
{ BIT_PUT, 0, 15, },
{ BIT_PUT, 0, 23, },
{ BIT_PUT_UE, 17, 0, },
{ BIT_PUT_SE, 9, 0, },
{ BIT_ALIGN_BYTE, 0, 0, },
};
void proc_bit_ops(MppWriteCtx *writer, BitOps *ops)
{
switch (ops->type) {
case BIT_PUT_NO03 : {
mpp_writer_put_raw_bits(writer, ops->val, ops->len);
} break;
case BIT_PUT : {
mpp_writer_put_bits(writer, ops->val, ops->len);
} break;
case BIT_PUT_UE : {
mpp_writer_put_ue(writer, ops->val);
} break;
case BIT_PUT_SE : {
mpp_writer_put_ue(writer, ops->val);
} break;
case BIT_ALIGN_BYTE : {
mpp_writer_trailing(writer);
} break;
default : {
mpp_err("invalid ops type %d\n", ops->type);
} break;
}
}
int main()
{
MPP_RET ret = MPP_ERR_UNKNOW;
void *data = NULL;
size_t size = BIT_WRITER_BUFFER_SIZE;
MppWriteCtx writer;
RK_U32 len_byte;
RK_U32 i;
RK_U32 buf_len = 0;
char buf[BIT_WRITER_BUFFER_SIZE];
mpp_log("mpp_bit_test start\n");
data = malloc(size);
if (NULL == data) {
mpp_err("mpp_bit_test malloc failed\n");
goto TEST_FAILED;
}
mpp_writer_init(&writer, data, size);
for (i = 0; i < MPP_ARRAY_ELEMS(bit_ops); i++)
proc_bit_ops(&writer, &bit_ops[i]);
len_byte = writer.byte_cnt;
for (i = 0; i < len_byte; i++) {
buf_len += snprintf(buf + buf_len, sizeof(buf) - buf_len,
"%02x ", writer.buffer[i]);
}
mpp_log("stream %s\n", buf);
ret = MPP_OK;
TEST_FAILED:
if (data)
free(data);
if (ret)
mpp_log("mpp_bit_test failed\n");
else
mpp_log("mpp_bit_test success\n");
return ret;
}