mirror of
https://github.com/nyanmisaka/mpp.git
synced 2026-01-24 04:50:39 +01:00
[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:
parent
042696c255
commit
53997e5cd8
5 changed files with 433 additions and 0 deletions
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
67
mpp/base/inc/mpp_bitwrite.h
Normal file
67
mpp/base/inc/mpp_bitwrite.h
Normal 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
235
mpp/base/mpp_bitwrite.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
128
mpp/base/test/mpp_bit_test.c
Normal file
128
mpp/base/test/mpp_bit_test.c
Normal 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;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue