[h264e_dpb]: Add H.264 encoder dpb/slice functions

1. Move hal h264e dpb/slice functions to codec.
2. The dpb functions support I frame gop interval, LTR interval, force
   LTR and generating reorder/marking syntax.

Change-Id: I42654f33c9628bb3228afb6acf56c85c984a377e
Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
This commit is contained in:
Herman Chen
2019-11-19 11:05:35 +08:00
parent ed13794d4d
commit 44f3604fb1
9 changed files with 1796 additions and 1721 deletions

View File

@@ -16,6 +16,8 @@ set(H264E_HDR
set(H264E_SRC
h264e_sps.c
h264e_pps.c
h264e_dpb.c
h264e_slice.c
h264e_api.c
)

File diff suppressed because it is too large Load Diff

View File

@@ -17,10 +17,7 @@
#ifndef __H264E_DPB_H__
#define __H264E_DPB_H__
#include "mpp_buffer.h"
#include "mpp_enc_refs.h"
#include "h264e_slice.h"
#include "h264e_sps.h"
/*
* H.264 encoder dpb structure info
@@ -38,58 +35,43 @@
*
*/
#define H264E_REF_MAX 16
#define H264E_MAX_BUF_CNT 2
#define MAX_GOP_SIZE 8
#define MAX_GOP_FMT_CNT (MAX_GOP_SIZE+1)
#define MAX_GOP_FMT_SIZE 5
#define MAX_GOP_FMT_BUF_STUFF 16
#define MAX_GOP_FMT_BUF_SIZE (MAX_GOP_FMT_CNT * MAX_GOP_FMT_SIZE + MAX_GOP_FMT_BUF_STUFF)
#define H264E_ST_GOP_FLAG (0x00000001)
#define H264E_ST_GOP_WITH_LT_REF (0x00000002)
#define H264E_LT_GOP_FLAG (0x00000010)
#define REF_BY_RECN(idx) (0x00000001 << idx)
#define REF_BY_REFR(idx) (0x00000001 << idx)
typedef struct H264eDpb_t H264eDpb;
typedef struct H264eDpbFrm_t H264eDpbFrm;
typedef struct H264eFrmBuf_t H264eFrmBuf;
typedef struct H264eFrmBufGrp_t H264eFrmBufGrp;
typedef struct H264eDpbFrmCfg_t {
/* request current frame to be IDR frame */
RK_S32 force_idr;
/*
* Split reference frame configure to two parts
* The first part is slice depended info like poc / frame_num, and frame
* type and flags.
* The other part is gop structure depended info like gop index, ref_status
* and ref_frm_index. This part is inited from dpb gop hierarchy info.
*/
typedef struct H264eDpbFrmInfo_t {
/*
* 0 - inter frame
* 1 - intra frame
*/
RK_U32 is_intra : 1;
/* request current frame to be a software all PSkip frame */
RK_S32 force_pskip;
/*
* Valid when is_intra is true
* 0 - normal intra frame
* 1 - IDR frame
* request current frame to be mark as a long-reference frame
* -1 - not forced to be marked as long-term reference frame
*/
RK_U32 is_idr : 1;
RK_S32 force_lt_idx;
/*
* 0 - mark as reference frame
* 1 - mark as non-refernce frame
* request current frame use long-term reference frame as its reference frame
* -1 - not forced to use long-term reference frame as reference frame
*/
RK_U32 is_non_ref : 1;
/*
* Valid when is_non_ref is false
* 0 - mark as short-term reference frame
* 1 - mark as long-term refernce frame
*/
RK_U32 is_lt_ref : 1;
RK_U32 stuff : 28;
} H264eDpbFrmInfo;
RK_S32 force_ref_lt_idx;
} H264eDpbFrmCfg;
typedef struct H264eDpbFrm_t {
H264eDpb *dpb;
RK_S32 slot_idx;
// frame index in frames
RK_S32 frm_cnt;
RK_S32 seq_idx;
// gop index in one gop structure
RK_S32 gop_idx;
RK_S32 gop_cnt;
@@ -121,17 +103,10 @@ typedef struct H264eDpbFrm_t {
RK_S32 ref_dist;
/* frame status */
MppEncFrmStatus info;
/* flag for marking process */
RK_S32 marked_unref;
EncFrmStatus status;
/*
* ENC_FRAME_TYPE in mpp_rc.h
* 0 - INTER_P_FRAME
* 1 - INTER_B_FRAME
* 2 - INTRA_FRAME
*/
RK_S32 frame_type;
/* H264_I_SLICE / H264_P_SLICE */
H264SliceType frame_type;
/* frame number from H264eSlice */
RK_S32 frame_num;
RK_S32 lt_idx;
@@ -139,33 +114,8 @@ typedef struct H264eDpbFrm_t {
RK_S32 poc;
/* pts from input MppFrame */
RK_S64 pts;
H264eFrmBuf *buf;
} H264eDpbFrm;
typedef struct H264eFrmBuf_t {
RK_U32 is_used;
// buf0 for normal pixel buffer
// buf1 for scaled buffer
MppBuffer buf[H264E_MAX_BUF_CNT];
} H264eFrmBuf;
typedef struct H264eFrmBufGrp_t {
MppBufferGroup group;
// buffer count for each frame buffers
RK_U32 count;
// buffer size for each buffer in frame buffers
RK_U32 size[H264E_MAX_BUF_CNT];
// frame buffer set
H264eFrmBuf bufs[H264E_REF_MAX];
} H264eFrmBufGrp;
typedef struct H264eDpbCfg_t {
RK_S32 ref_frm_num;
RK_S32 log2_max_frm_num;
RK_S32 log2_max_poc_lsb;
} H264eDpbCfg;
/*
* dpb frame arrangement
*
@@ -177,7 +127,8 @@ typedef struct H264eDpbCfg_t {
* next frame encoding.
*/
typedef struct H264eDpb_t {
H264eDpbCfg cfg;
H264eReorderInfo *reorder;
H264eMarkingInfo *marking;
/*
* ref_frm_num - max reference frame number
@@ -190,38 +141,51 @@ typedef struct H264eDpb_t {
RK_S32 max_frm_num;
RK_S32 max_poc_lsb;
// status and count for one gop structure
RK_S32 seq_cnt;
RK_S32 seq_idx;
RK_S32 gop_len;
RK_S32 gop_cnt;
RK_S32 gop_idx;
/*
* dpb mode
* 0 - Default two frame swap mode. Only use refr and recn frame
* 1 - Dpb with user hierarchy mode
*/
RK_S32 mode;
RK_S32 curr_frm_num;
RK_S32 next_frm_num;
// overall frame counter
RK_S32 seq_idx;
// status and count for one gop structure
// idr_gop - for intra / IDR frame group of picture
// st_gop - for short-term reference group of picture in TSVC mode
// lt_gop - for long-term reference group of picture in SVC mode
RK_S32 idr_gop_len;
RK_S32 idr_gop_cnt;
RK_S32 idr_gop_idx;
RK_S32 st_gop_len;
RK_S32 st_gop_cnt;
RK_S32 st_gop_idx;
RK_S32 lt_gop_len;
RK_S32 lt_gop_cnt;
RK_S32 lt_gop_idx;
RK_S32 poc_lsb;
RK_S32 last_frm_num;
RK_S32 lt_ref_idx;
// slot counter
RK_S32 total_cnt;
RK_S32 max_st_cnt;
RK_S32 max_lt_cnt;
RK_S32 curr_idx;
// for reference frame list generation
RK_S32 dpb_size;
RK_S32 st_size;
RK_S32 lt_size;
H264eDpbFrm *curr;
H264eDpbFrm *list[H264E_REF_MAX];
H264eDpbFrm *stref[H264E_REF_MAX];
H264eDpbFrm *ltref[H264E_REF_MAX];
RK_S32 need_reorder;
H264eDpbFrm *refr;
H264eDpbFrm *list[H264E_MAX_REFS_CNT];
H264eDpbFrm *stref[H264E_MAX_REFS_CNT];
H264eDpbFrm *ltref[H264E_MAX_REFS_CNT];
RK_S32 curr_max_lt_idx;
RK_S32 next_max_lt_idx;
// for mmco unreferece marking process
RK_U32 unref_cnt;
H264eDpbFrm *unref[H264E_REF_MAX];
/*
* ref_inf bit info:
* bit 0 - intra flag
@@ -229,36 +193,51 @@ typedef struct H264eDpb_t {
* bit 2 - non-ref flag
* bit 3 - long-term flag
*/
MppEncFrmStatus ref_inf[MAX_GOP_FMT_CNT];
EncFrmStatus ref_inf[MAX_GOP_FMT_CNT];
RK_U32 ref_sta[MAX_GOP_FMT_CNT];
RK_U32 ref_cnt[MAX_GOP_FMT_CNT];
RK_S32 ref_dist[MAX_GOP_FMT_CNT];
// buffer management
H264eFrmBufGrp buf_grp;
// frame storage
H264eDpbFrm *frames;
H264eDpbFrm frames[H264E_MAX_REFS_CNT + 1];
} H264eDpb;
#ifdef __cplusplus
extern "C" {
#endif
MPP_RET h264e_dpb_init(H264eDpb **dpb, H264eDpbCfg *cfg);
MPP_RET h264e_dpb_init(H264eDpb *dpb, H264eReorderInfo *reorder, H264eMarkingInfo *marking);
MPP_RET h264e_dpb_deinit(H264eDpb *dpb);
MPP_RET h264e_dpb_setup_buf_size(H264eDpb *dpb, RK_U32 size[], RK_U32 count);
MPP_RET h264e_dpb_setup_hier(H264eDpb *dpb, MppEncHierCfg *cfg);
/* copy function is for dpb backup and restore */
MPP_RET h264e_dpb_copy(H264eDpb *dst, H264eDpb *src);
H264eDpbFrm *h264e_dpb_get_curr(H264eDpb *dpb, RK_S32 new_seq);
H264eDpbFrm *h264e_dpb_get_refr(H264eDpbFrm *frm);
/*
* Setup gop group config using MppEncCfgSet and SynH264eSps
* This config function will be called on the following cases:
*
* 1. sps reference number changed which will change totol dpb slot count
* 2. gop size changed which will change the max frame number and max poc lsb
* 3. gop ref relation changed will change tsvc / vgop setup
*/
MPP_RET h264e_dpb_set_cfg(H264eDpb *dpb, MppEncCfgSet* cfg, SynH264eSps *sps);
/*
* Setup current frame config using flags
* This config function will be called before each frame is encoded:
*
* idr - current frame is force to IDR or not
* lt_ref - current frame is marked as longterm reference
*/
MPP_RET h264e_dpb_set_curr(H264eDpb *dpb, H264eDpbFrmCfg *cfg);
/*
* Setup current frame and reference frame
*/
void h264e_dpb_build_list(H264eDpb *dpb);
void h264e_dpb_build_marking(H264eDpb *dpb);
void h264e_dpb_curr_ready(H264eDpb *dpb);
MppBuffer h264e_dpb_frm_get_buf(H264eDpbFrm *frm, RK_S32 index);
#define h264e_dpb_dump_frms(dpb) h264e_dpb_dump_frm(dpb, __FUNCTION__)
void h264e_dpb_dump_frm(H264eDpb *dpb, const char *caller);

View File

@@ -0,0 +1,634 @@
/*
* 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 "h264e_slice"
#include <string.h>
#include "mpp_mem.h"
#include "mpp_bitread.h"
#include "mpp_bitwrite.h"
#include "h264e_debug.h"
#include "h264e_slice.h"
#define FP_FIFO_IS_FULL
void h264e_slice_init(H264eSlice *slice, H264eReorderInfo *reorder,
H264eMarkingInfo *marking)
{
memset(slice, 0, sizeof(*slice));
slice->num_ref_idx_active = 1;
slice->reorder = reorder;
slice->marking = marking;
}
RK_S32 h264e_slice_update(H264eSlice *slice, MppEncCfgSet *cfg,
SynH264eSps *sps, H264eDpbFrm *frm)
{
MppEncH264Cfg *h264 = &cfg->codec.h264;
slice->log2_max_frame_num = sps->log2_max_frame_num_minus4 + 4;
slice->log2_max_poc_lsb = sps->log2_max_poc_lsb_minus4 + 4;
slice->entropy_coding_mode = h264->entropy_coding_mode;
slice->nal_reference_idc = H264_NALU_PRIORITY_HIGH;;
slice->nalu_type = H264_NALU_TYPE_IDR;
slice->first_mb_in_slice = 0;
slice->slice_type = (frm->status.is_idr) ? (H264_I_SLICE) : (H264_P_SLICE);
slice->pic_parameter_set_id = 0;
slice->frame_num = frm->frame_num;
slice->num_ref_idx_override = 0;
slice->qp_delta = 0;
slice->cabac_init_idc = h264->entropy_coding_mode ? h264->cabac_init_idc : -1;
slice->disable_deblocking_filter_idc = h264->deblock_disable;
slice->slice_alpha_c0_offset_div2 = h264->deblock_offset_alpha;
slice->slice_beta_offset_div2 = h264->deblock_offset_beta;
slice->idr_flag = frm->status.is_idr;
if (slice->idr_flag) {
slice->idr_pic_id = slice->next_idr_pic_id;
slice->next_idr_pic_id++;
if (slice->next_idr_pic_id >= 16)
slice->next_idr_pic_id = 0;
}
slice->pic_order_cnt_lsb = frm->poc;
slice->num_ref_idx_active = 1;
return MPP_OK;
}
MPP_RET h264e_reorder_init(H264eReorderInfo *reorder)
{
reorder->size = H264E_MAX_REFS_CNT;
reorder->pos_wr = 0;
reorder->pos_rd = reorder->size;
return MPP_OK;
}
MPP_RET h264e_reorder_wr_op(H264eReorderInfo *info, H264eRplmo *op)
{
if (info->pos_rd == info->pos_wr)
return MPP_NOK;
RK_S32 pos_wr = info->pos_wr;
if (pos_wr >= info->size)
pos_wr -= info->size;
info->ops[pos_wr] = *op;
info->pos_wr++;
if (info->pos_wr >= info->size * 2)
info->pos_wr = 0;
return MPP_OK;
}
MPP_RET h264e_reorder_rd_op(H264eReorderInfo *info, H264eRplmo *op)
{
if (info->pos_rd - info->pos_wr == info->size ||
info->pos_wr - info->pos_rd == info->size)
return MPP_NOK;
RK_S32 pos_rd = info->pos_rd;
if (pos_rd >= info->size)
pos_rd -= info->size;
*op = info->ops[pos_rd];
info->pos_rd++;
if (info->pos_rd >= info->size * 2)
info->pos_rd = 0;
return MPP_OK;
}
MPP_RET h264e_marking_init(H264eMarkingInfo *marking)
{
marking->idr_flag = 0;
marking->no_output_of_prior_pics = 1;
marking->long_term_reference_flag = 0;
marking->adaptive_ref_pic_buffering = 0;
marking->size = MAX_H264E_MMCO_CNT;
marking->pos_wr = 0;
marking->pos_rd = marking->size;
marking->count = 0;
return MPP_OK;
}
RK_S32 h264e_marking_is_empty(H264eMarkingInfo *info)
{
return (info->pos_rd - info->pos_wr == info->size ||
info->pos_wr - info->pos_rd == info->size) ? (1) : (0);
}
RK_S32 h264e_marking_is_full(H264eMarkingInfo *info)
{
return (info->pos_rd == info->pos_wr) ? (1) : (0);
}
MPP_RET h264e_marking_wr_op(H264eMarkingInfo *info, H264eMmco *op)
{
if (h264e_marking_is_full(info))
return MPP_NOK;
RK_S32 pos_wr = info->pos_wr;
if (pos_wr >= info->size)
pos_wr -= info->size;
info->ops[pos_wr] = *op;
info->pos_wr++;
if (info->pos_wr >= info->size * 2)
info->pos_wr = 0;
info->count++;
return MPP_OK;
}
MPP_RET h264e_marking_rd_op(H264eMarkingInfo *info, H264eMmco *op)
{
if (h264e_marking_is_empty(info))
return MPP_NOK;
RK_S32 pos_rd = info->pos_rd;
if (pos_rd >= info->size)
pos_rd -= info->size;
*op = info->ops[pos_rd];
info->pos_rd++;
if (info->pos_rd >= info->size * 2)
info->pos_rd = 0;
info->count--;
return MPP_OK;
}
void write_marking(MppWriteCtx *s, H264eMarkingInfo *marking)
{
if (marking->idr_flag) {
/* no_output_of_prior_pics_flag */
mpp_writer_put_bits(s, marking->no_output_of_prior_pics, 1);
/* long_term_reference_flag */
mpp_writer_put_bits(s, marking->long_term_reference_flag, 1);
// clear long_term_reference_flag flag
marking->long_term_reference_flag = 0;
} else {
h264e_dbg_mmco("mmco count %d\n", marking->count);
if (!h264e_marking_is_empty(marking)) {
/* adaptive_ref_pic_marking_mode_flag */
mpp_writer_put_bits(s, 1, 1);
while (marking->count) {
H264eMmco mmco;
h264e_marking_rd_op(marking, &mmco);
/* memory_management_control_operation */
mpp_writer_put_ue(s, mmco.mmco);
switch (mmco.mmco) {
case 1 : {
/* difference_of_pic_nums_minus1 */
mpp_writer_put_ue(s, mmco.difference_of_pic_nums_minus1);
} break;
case 2 : {
/* long_term_pic_num */
mpp_writer_put_ue(s, mmco.long_term_pic_num );
} break;
case 3 : {
/* difference_of_pic_nums_minus1 */
mpp_writer_put_ue(s, mmco.difference_of_pic_nums_minus1);
/* long_term_frame_idx */
mpp_writer_put_ue(s, mmco.long_term_frame_idx );
} break;
case 4 : {
/* max_long_term_frame_idx_plus1 */
mpp_writer_put_ue(s, mmco.max_long_term_frame_idx_plus1);
} break;
case 5 : {
} break;
case 6 : {
/* long_term_frame_idx */
mpp_writer_put_ue(s, mmco.long_term_frame_idx);
} break;
default : {
mpp_err_f("invalid mmco %d\n", mmco.mmco);
} break;
}
marking->count--;
}
/* memory_management_control_operation */
mpp_writer_put_ue(s, 0);
} else {
/* adaptive_ref_pic_marking_mode_flag */
mpp_writer_put_bits(s, 0, 1);
}
}
}
RK_S32 h264e_slice_read(H264eSlice *slice, void *p, RK_S32 size)
{
BitReadCtx_t bit;
RK_S32 ret = 0;
RK_S32 val = 0;
RK_S32 bit_cnt = 0;
mpp_set_bitread_ctx(&bit, p, size);
/* start_code */
ret |= mpp_read_longbits(&bit, 32, (RK_U32 *)&val);
/* forbidden_zero_bit */
ret |= mpp_read_bits(&bit, 1, &val);
/* nal_ref_idc */
ret |= mpp_read_bits(&bit, 2, &slice->nal_reference_idc);
/* nal_unit_type */
ret |= mpp_read_bits(&bit, 5, &slice->nalu_type);
/* first_mb_nr */
ret = mpp_read_ue(&bit, &slice->first_mb_in_slice);
/* slice_type */
ret |= mpp_read_ue(&bit, &slice->slice_type);
/* pic_parameter_set_id */
ret |= mpp_read_ue(&bit, &slice->pic_parameter_set_id);
/* frame_num */
/* NOTE: vpu hardware fix 16 bit frame_num */
ret |= mpp_read_bits(&bit, 16, &slice->frame_num);
slice->idr_flag = (slice->nalu_type == 5);
if (slice->idr_flag) {
/* idr_pic_id */
ret |= mpp_read_ue(&bit, &slice->idr_pic_id);
}
// pic_order_cnt_type here
// vpu hardware is always zero. Just ignore
// NOTE: Only P slice has num_ref_idx_override flag and ref_pic_list_modification flag
if (slice->slice_type == 0) {
/* num_ref_idx_override */
ret |= mpp_read_bits(&bit, 1, &slice->num_ref_idx_override);
/* ref_pic_list_modification_flag */
ret |= mpp_read_bits(&bit, 1, &slice->ref_pic_list_modification_flag);
}
// NOTE: vpu hardware is always zero
slice->ref_pic_list_modification_flag = 0;
if (slice->nal_reference_idc) {
if (slice->idr_flag) {
/* no_output_of_prior_pics */
ret |= mpp_read_bits(&bit, 1, &slice->no_output_of_prior_pics);
/* long_term_reference_flag */
ret |= mpp_read_bits(&bit, 1, &slice->long_term_reference_flag);
} else {
/* adaptive_ref_pic_buffering */
ret |= mpp_read_bits(&bit, 1, &slice->adaptive_ref_pic_buffering);
mpp_assert(slice->adaptive_ref_pic_buffering == 0);
}
}
if (slice->entropy_coding_mode && slice->slice_type != H264_I_SLICE) {
/* cabac_init_idc */
ret |= mpp_read_ue(&bit, &slice->cabac_init_idc);
}
/* qp_delta */
ret |= mpp_read_se(&bit, &slice->qp_delta);
/* disable_deblocking_filter_idc */
ret |= mpp_read_ue(&bit, &slice->disable_deblocking_filter_idc);
/* slice_alpha_c0_offset_div2 */
ret |= mpp_read_se(&bit, &slice->slice_alpha_c0_offset_div2);
/* slice_beta_offset_div2 */
ret |= mpp_read_se(&bit, &slice->slice_beta_offset_div2);
h264e_dbg_slice("non-aligned used bit %d\n", bit.used_bits);
if (slice->entropy_coding_mode) {
if (bit.num_remaining_bits_in_curr_byte_) {
RK_U32 tmp = bit.num_remaining_bits_in_curr_byte_;
/* cabac_aligned_bit */
ret |= mpp_read_bits(&bit, tmp, &val);
}
}
bit_cnt = bit.used_bits;
h264e_dbg_slice("total aligned used bit %d\n", bit_cnt);
return bit_cnt;
}
RK_S32 h264e_slice_write(H264eSlice *slice, void *p, RK_U32 size)
{
MppWriteCtx stream;
MppWriteCtx *s = &stream;
RK_S32 i;
RK_S32 bitCnt = 0;
H264eMarkingInfo *marking = slice->marking;
H264eRplmo rplmo;
MPP_RET ret;
mpp_writer_init(s, p, size);
RK_U8 *tmp = (RK_U8 *)s->buffer;
/* nal header */
/* start_code_prefix 00 00 00 01 */
mpp_writer_put_raw_bits(s, 0, 24);
mpp_writer_put_raw_bits(s, 1, 8);
/* forbidden_zero_bit */
mpp_writer_put_raw_bits(s, 0, 1);
/* nal_reference_idc */
mpp_writer_put_raw_bits(s, slice->nal_reference_idc, 2);
/* nalu_type */
mpp_writer_put_raw_bits(s, slice->nalu_type, 5);
/* slice header */
/* start_mb_nr */
mpp_writer_put_ue(s, slice->first_mb_in_slice);
/* slice_type */
mpp_writer_put_ue(s, slice->slice_type);
/* pic_parameter_set_id */
mpp_writer_put_ue(s, slice->pic_parameter_set_id);
/* frame_num */
mpp_writer_put_bits(s, slice->frame_num, 16);
if (slice->nalu_type == 5) {
/* idr_pic_id */
mpp_writer_put_ue(s, slice->idr_pic_id);
marking->idr_flag = 1;
} else
marking->idr_flag = 0;
// Force to use poc type 0 here
{
RK_S32 pic_order_cnt_lsb = slice->pic_order_cnt_lsb;
RK_S32 max_poc_lsb = (1 << slice->log2_max_poc_lsb) - 1;
if (pic_order_cnt_lsb >= max_poc_lsb)
pic_order_cnt_lsb -= max_poc_lsb;
/* pic_order_cnt_lsb */
mpp_writer_put_bits(s, pic_order_cnt_lsb, 16);
}
/* read reorder and check */
ret = h264e_reorder_rd_op(slice->reorder, &rplmo);
if (slice->slice_type == H264_P_SLICE && !ret) {
/* num_ref_idx_override */
mpp_writer_put_bits(s, slice->num_ref_idx_override, 1);
/* ref_pic_list_reordering */
mpp_writer_put_bits(s, 1, 1);
slice->ref_pic_list_modification_flag = 1;
} else
slice->ref_pic_list_modification_flag = 0;
if (slice->slice_type == H264_I_SLICE)
mpp_assert(slice->ref_pic_list_modification_flag == 0);
if (slice->ref_pic_list_modification_flag) {
mpp_assert(ret == MPP_OK);
/* modification_of_pic_nums_idc */
mpp_writer_put_ue(s, rplmo.modification_of_pic_nums_idc);
switch (rplmo.modification_of_pic_nums_idc) {
case 0 :
case 1 : {
/* abs_diff_pic_num_minus1 */
mpp_writer_put_ue(s, rplmo.abs_diff_pic_num_minus1);
} break;
case 2 : {
/* long_term_pic_idx */
mpp_writer_put_ue(s, rplmo.long_term_pic_idx);
} break;
default : {
mpp_err_f("invalid modification_of_pic_nums_idc %d\n",
rplmo.modification_of_pic_nums_idc);
} break;
}
/* modification_of_pic_nums_idc */
mpp_writer_put_ue(s, 3);
}
// NOTE: ignore nal ref idc here
h264e_dbg_mmco("nal_reference_idc %d idr_flag %d\n",
slice->nal_reference_idc, slice->idr_flag);
if (slice->nal_reference_idc)
write_marking(s, marking);
if (slice->entropy_coding_mode && slice->slice_type != H264_I_SLICE) {
/* cabac_init_idc */
mpp_writer_put_ue(s, slice->cabac_init_idc);
}
/* qp_delta */
mpp_writer_put_se(s, slice->qp_delta);
/* disable_deblocking_filter_idc */
mpp_writer_put_ue(s, 0);
/* slice_alpha_c0_offset_div2 */
mpp_writer_put_se(s, 0);
/* slice_beta_offset_div2 */
mpp_writer_put_se(s, 0);
bitCnt = s->buffered_bits + s->byte_cnt * 8;
if (s->buffered_bits) {
// NOTE: only have aligned bit on cabac mode but cavlc also need to write byte cache to memory
RK_S32 left = (8 - s->buffered_bits);
for (i = 0; i < left; i++) {
/* align_bit */
mpp_writer_put_bits(s, 1, 1);
}
}
// update on cabac mode
if (slice->entropy_coding_mode)
bitCnt = s->buffered_bits + s->byte_cnt * 8;
RK_S32 pos = 0;
char log[256];
pos = sprintf(log + pos, "sw stream: ");
for (i = 0; i < 16; i ++) {
pos += sprintf(log + pos, "%02x ", tmp[i]);
}
pos += sprintf(log + pos, "\n");
h264e_dbg_slice(log);
return bitCnt;
}
static RK_S32 frame_no = 0;
RK_S32 h264e_slice_move(RK_U8 *dst, RK_U8 *src, RK_S32 dst_bit, RK_S32 src_bit, RK_S32 src_size)
{
RK_S32 dst_byte = dst_bit / 8;
RK_S32 src_byte = src_bit / 8;
RK_S32 dst_bit_r = dst_bit & 7;
RK_S32 src_bit_r = src_bit & 7;
RK_S32 src_len = src_size - src_byte;
RK_S32 diff_len = 0;
if (src_bit_r == 0 && dst_bit_r == 0) {
// direct copy
if (h264e_debug & H264E_DBG_SLICE)
mpp_log_f("direct copy %p -> %p %d\n", src, dst, src_len);
memcpy(dst + dst_byte, src + src_byte, src_len);
return diff_len;
}
RK_U8 *psrc = src + src_byte;
RK_U8 *pdst = dst + dst_byte;
RK_U16 tmp16a, tmp16b, tmp16c, last_tmp;
RK_U8 tmp0, tmp1;
RK_U32 loop = src_len;
RK_U32 i = 0;
RK_U32 src_zero_cnt = 0;
RK_U32 dst_zero_cnt = 0;
RK_U32 dst_len = 0;
if (h264e_debug & H264E_DBG_SLICE)
mpp_log("bit [%d %d] [%d %d] loop %d\n", src_bit, dst_bit,
src_bit_r, dst_bit_r, loop);
last_tmp = pdst[0] >> (8 - dst_bit_r) << (8 - dst_bit_r);
for (i = 0; i < loop; i++) {
if (psrc[0] == 0) {
src_zero_cnt++;
} else {
src_zero_cnt = 0;
}
// tmp0 tmp1 is next two non-aligned bytes from src
tmp0 = psrc[0];
tmp1 = (i < loop - 1) ? psrc[1] : 0;
if (src_zero_cnt >= 2 && tmp1 == 3) {
if (h264e_debug & H264E_DBG_SLICE)
mpp_log("found 03 at src pos %d %02x %02x %02x %02x %02x %02x %02x %02x\n",
i, psrc[-2], psrc[-1], psrc[0], psrc[1], psrc[2],
psrc[3], psrc[4], psrc[5]);
psrc++;
i++;
tmp1 = psrc[1];
src_zero_cnt = 0;
diff_len--;
}
// get U16 data
tmp16a = ((RK_U16)tmp0 << 8) | (RK_U16)tmp1;
if (src_bit_r) {
tmp16b = tmp16a << src_bit_r;
} else {
tmp16b = tmp16a;
}
if (dst_bit_r)
tmp16c = tmp16b >> dst_bit_r | (last_tmp >> (8 - dst_bit_r) << (16 - dst_bit_r));
else
tmp16c = tmp16b;
pdst[0] = (tmp16c >> 8) & 0xFF;
pdst[1] = tmp16c & 0xFF;
if (h264e_debug & H264E_DBG_SLICE) {
if (i < 10) {
mpp_log("%03d src [%04x] -> [%04x] + last [%04x] -> %04x\n", i, tmp16a, tmp16b, last_tmp, tmp16c);
}
if (i >= loop - 10) {
mpp_log("%03d src [%04x] -> [%04x] + last [%04x] -> %04x\n", i, tmp16a, tmp16b, last_tmp, tmp16c);
}
}
if (dst_zero_cnt == 2 && pdst[0] <= 0x3) {
if (h264e_debug & H264E_DBG_SLICE)
mpp_log("found 03 at dst frame %d pos %d\n", frame_no, dst_len);
pdst[2] = pdst[1];
pdst[1] = pdst[0];
pdst[0] = 0x3;
pdst++;
diff_len++;
dst_len++;
dst_zero_cnt = 0;
}
if (pdst[0] == 0)
dst_zero_cnt++;
else
dst_zero_cnt = 0;
last_tmp = tmp16c;
psrc++;
pdst++;
dst_len++;
}
frame_no++;
return diff_len;
}

View File

@@ -0,0 +1,59 @@
/*
* 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.
*/
#ifndef __H264E_SLICE_H__
#define __H264E_SLICE_H__
#include "mpp_enc_cfg.h"
#include "h264e_syntax_new.h"
#include "h264e_dpb.h"
#ifdef __cplusplus
extern "C" {
#endif
MPP_RET h264e_reorder_init(H264eReorderInfo *reorder);
MPP_RET h264e_marking_init(H264eMarkingInfo *marking);
/*
* h264e_slice_update is called only on cfg is update.
* When cfg has no changes just use slice next to setup
*/
void h264e_slice_init(H264eSlice *slice, H264eReorderInfo *reorder,
H264eMarkingInfo *marking);
RK_S32 h264e_slice_update(H264eSlice *slice, MppEncCfgSet *cfg,
SynH264eSps *sps, H264eDpbFrm *frm);
/* reorder context for dpb */
MPP_RET h264e_reorder_wr_op(H264eReorderInfo *info, H264eRplmo *op);
MPP_RET h264e_reorder_rd_op(H264eReorderInfo *info, H264eRplmo *op);
/* mmco context for dpb */
MPP_RET h264e_marking_wr_op(H264eMarkingInfo *info, H264eMmco *op);
MPP_RET h264e_marking_rd_op(H264eMarkingInfo *info, H264eMmco *op);
RK_S32 h264e_slice_read(H264eSlice *slice, void *p, RK_S32 size);
RK_S32 h264e_slice_write(H264eSlice *slice, void *p, RK_U32 size);
RK_S32 h264e_slice_move(RK_U8 *dst, RK_U8 *src, RK_S32 dst_bit, RK_S32 src_bit,
RK_S32 src_size);
#ifdef __cplusplus
}
#endif
#endif /* __H264E_SLICE_H__ */

View File

@@ -11,8 +11,6 @@ set(HAL_H264E_HDR
# hal h264 encoder sourse
set(HAL_H264E_SRC
h264e_dpb.c
h264e_slice.c
h264e_stream.c
hal_h264e_com.c
hal_h264e_api.c

View File

@@ -1,815 +0,0 @@
/*
* 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 "h264e_dpb"
#include <string.h>
#include "mpp_log.h"
#include "mpp_mem.h"
#include "mpp_common.h"
#include "hal_h264e_com.h"
#include "h264e_dpb.h"
H264eFrmBuf *h264e_dpb_frm_buf_get(H264eFrmBufGrp *grp)
{
RK_U32 i;
for (i = 0; i < H264E_REF_MAX; i++) {
if (!grp->bufs[i].is_used) {
grp->bufs[i].is_used = 1;
return &grp->bufs[i];
}
}
mpp_err_f("failed to get buffer for dpb frame\n");
return NULL;
}
MPP_RET h264e_dpb_frm_buf_put(H264eFrmBufGrp *grp, H264eFrmBuf *buf)
{
mpp_assert(buf->is_used);
buf->is_used = 0;
(void)grp;
return MPP_OK;
}
/* get buffer at init */
MPP_RET h264e_dpb_init_curr(H264eDpb *dpb, H264eDpbFrm *frm)
{
H264eFrmBufGrp *buf_grp = &dpb->buf_grp;
mpp_assert(!frm->on_used);
frm->dpb = dpb;
frm->ref_status = 0;
frm->ref_count = 0;
memset(&frm->info, 0, sizeof(frm->info));
if (!frm->buf) {
RK_U32 i;
H264eFrmBuf *buf = h264e_dpb_frm_buf_get(buf_grp);
for (i = 0; i < buf_grp->count; i++) {
mpp_buffer_get(buf_grp->group, &buf->buf[i], buf_grp->size[i]);
mpp_assert(buf->buf[i]);
}
frm->buf = buf;
}
frm->inited = 1;
return MPP_OK;
}
/* put buffer at deinit */
MPP_RET h264e_dpb_frm_deinit(H264eDpbFrm *frm)
{
RK_U32 i;
H264eDpb *dpb = frm->dpb;
H264eFrmBufGrp *buf_grp = &dpb->buf_grp;
H264eFrmBuf *buf = frm->buf;
h264e_dpb_dbg_f("enter %d\n", frm->frm_cnt);
for (i = 0; i < buf_grp->count; i++) {
mpp_assert(buf->buf[i]);
mpp_buffer_put(buf->buf[i]);
buf->buf[i] = NULL;
}
h264e_dpb_frm_buf_put(buf_grp, buf);
frm->inited = 0;
return MPP_OK;
}
MppBuffer h264e_dpb_frm_get_buf(H264eDpbFrm *frm, RK_S32 index)
{
H264eFrmBuf *buf = frm->buf;
if (NULL == buf)
return NULL;
mpp_assert(buf->is_used);
mpp_assert(index >= 0 && index < H264E_MAX_BUF_CNT);
mpp_assert(buf->buf[index]);
return buf->buf[index];
}
static void h264e_dpb_dump_hier(H264eDpb *dpb)
{
RK_S32 i = 0;
mpp_log_f("dpb %p gop length %d\n", dpb, dpb->gop_len);
for (i = 0; i < dpb->gop_len + 1; i++) {
mpp_log_f("hier %d cnt %2d status 0x%03x dist %d\n", i,
dpb->ref_cnt[i], dpb->ref_sta[i], dpb->ref_dist[i]);
}
}
void h264e_dpb_dump_frm(H264eDpb *dpb, const char *caller)
{
RK_S32 i = 0;
mpp_log_f("dump dpb frame info in %s\n", caller);
mpp_log_f("dpb %p total count %d\n", dpb, dpb->total_cnt);
mpp_log_f("dpb status - init use cnt gop idx type idr ref lt idx sta cnt\n", dpb, dpb->total_cnt);
for (i = 0; i < dpb->total_cnt; i++) {
H264eDpbFrm *frm = &dpb->frames[i];
if (i == 0) {
mpp_log_f("short-term reference frame:\n");
} else if (i == dpb->max_st_cnt) {
mpp_log_f("long-term reference frame:\n");
} else if (i == dpb->curr_idx) {
mpp_log_f("current frame:\n");
}
if (!frm->inited)
continue;
mpp_log_f("frm slot %2d %-4d %-3d %-3d %-3d %-3d %-4d %-3d %-3d %-2d %-3d %-3x %-3d\n",
i,
frm->inited,
frm->on_used,
frm->frm_cnt,
frm->gop_cnt,
frm->gop_idx,
frm->frame_type,
frm->info.is_idr,
!frm->info.is_non_ref,
frm->info.is_lt_ref,
frm->lt_idx,
frm->ref_status,
frm->ref_count);
}
}
void h264e_dpb_dump_listX(H264eDpbFrm **list, RK_S32 count)
{
RK_S32 i;
for (i = 0; i < count; i++) {
H264eDpbFrm *frm = list[i];
mpp_log_f("list slot %d %-4d %-3d %-3d %-3d %-4d %-3d %-3d %-2d %-3d %-3x %-3d\n",
i,
frm->inited,
frm->on_used,
frm->frm_cnt,
frm->gop_idx,
frm->frame_type,
frm->info.is_idr,
!frm->info.is_non_ref,
frm->info.is_lt_ref,
frm->lt_idx,
frm->ref_status,
frm->ref_count);
}
}
void h264e_dpb_dump_list(H264eDpb *dpb)
{
mpp_log_f("dump dpb list info\n");
mpp_log_f("dpb size %d st size %d lt size %d\n",
dpb->dpb_size, dpb->st_size, dpb->lt_size);
if (dpb->dpb_size) {
mpp_log_f("list status - init use cnt gop type idr ref lt idx sta cnt\n", dpb, dpb->total_cnt);
h264e_dpb_dump_listX(dpb->list, dpb->dpb_size);
}
}
MPP_RET h264e_dpb_init(H264eDpb **dpb, H264eDpbCfg *cfg)
{
MPP_RET ret = MPP_OK;
H264eDpb *p = NULL;
if (NULL == dpb || NULL == cfg) {
mpp_err_f("invalid parameter %p %p\n", dpb, cfg);
return MPP_ERR_VALUE;
}
h264e_dpb_dbg_f("enter\n");
h264e_dpb_dbg_f("max ref frm num %d\n", cfg->ref_frm_num);
h264e_dpb_dbg_f("log2 max frm num %d\n", cfg->log2_max_frm_num);
h264e_dpb_dbg_f("log2 max poc lsb %d\n", cfg->log2_max_poc_lsb);
if (cfg->ref_frm_num < 0 || cfg->ref_frm_num > H264E_REF_MAX ||
cfg->log2_max_frm_num < 0 || cfg->log2_max_frm_num > 16 ||
cfg->log2_max_poc_lsb < 0 || cfg->log2_max_poc_lsb > 16) {
mpp_err_f("invalid config value %d %d %d\n", cfg->ref_frm_num,
cfg->log2_max_frm_num, cfg->log2_max_poc_lsb);
return MPP_ERR_VALUE;
}
RK_S32 max_st_cnt = cfg->ref_frm_num;
RK_S32 max_lt_cnt = cfg->ref_frm_num;
RK_S32 total_cnt = max_st_cnt + max_lt_cnt + 1;
p = mpp_calloc_size(H264eDpb, sizeof(H264eDpb) +
total_cnt * sizeof(H264eDpbFrm));
if (NULL == p)
return MPP_ERR_MALLOC;
p->cfg = *cfg;
p->ref_frm_num = max_st_cnt;
p->max_frm_num = (1 << cfg->log2_max_frm_num) - 1;
p->max_poc_lsb = (1 << cfg->log2_max_poc_lsb) - 1;
p->total_cnt = total_cnt;
p->max_st_cnt = max_st_cnt;
p->max_lt_cnt = max_lt_cnt;
p->curr_idx = total_cnt - 1;
p->frames = (H264eDpbFrm *)(p + 1);
ret = mpp_buffer_group_get_internal(&p->buf_grp.group, MPP_BUFFER_TYPE_ION);
mpp_assert(ret == MPP_OK);
mpp_assert(p->buf_grp.group);
mpp_assert(dpb);
*dpb = p;
h264e_dpb_dbg_f("leave %p\n", p);
return ret;
}
MPP_RET h264e_dpb_deinit(H264eDpb *dpb)
{
RK_S32 i;
h264e_dpb_dbg_f("enter %p\n", dpb);
for (i = 0; i < dpb->total_cnt; i++) {
if (dpb->frames[i].inited)
h264e_dpb_frm_deinit(&dpb->frames[i]);
}
if (dpb->buf_grp.group)
mpp_buffer_group_put(dpb->buf_grp.group);
MPP_FREE(dpb);
h264e_dpb_dbg_f("leave\n");
return MPP_OK;
}
MPP_RET h264e_dpb_setup_buf_size(H264eDpb *dpb, RK_U32 size[], RK_U32 count)
{
RK_U32 i;
H264eFrmBufGrp *buf_grp = &dpb->buf_grp;
if (count > H264E_MAX_BUF_CNT) {
mpp_err_f("invalid count %d\n", count);
return MPP_NOK;
}
for (i = 0; i < count; i++) {
buf_grp->size[i] = size[i];
h264e_dpb_dbg_f("size[%d] %d\n", i, size[i]);
}
buf_grp->count = count;
return MPP_OK;
}
MPP_RET h264e_dpb_setup_hier(H264eDpb *dpb, MppEncHierCfg *cfg)
{
// update gop hierarchy reference status and each frame counter
RK_S32 i;
MppEncFrmRefInfo *info;
MppEncFrmRefInfo *base;
memset(dpb->ref_inf, 0, sizeof(dpb->ref_inf));
memset(dpb->ref_sta, 0, sizeof(dpb->ref_sta));
memset(dpb->ref_cnt, 0, sizeof(dpb->ref_cnt));
memset(dpb->ref_dist, 0, sizeof(dpb->ref_dist));
dpb->gop_len = cfg->length;
dpb->max_lt_idx = 0;
mpp_enc_get_hier_info(&info, cfg);
base = info;
for (i = 0; i < cfg->length + 1; i++, info++) {
RK_S32 ref_idx = info->ref_gop_idx;
// setup ref_status and ref_idx for new frame
dpb->ref_inf[i] = info->status;
dpb->ref_dist[i] = ref_idx - i;
if (!info->status.is_non_ref) {
dpb->ref_sta[i] |= REF_BY_RECN(i);
dpb->ref_cnt[i]++;
}
if (!info->status.is_non_ref && info->status.is_lt_ref) {
if (info->status.lt_idx > dpb->max_lt_idx) {
dpb->max_lt_idx = info->status.lt_idx;
h264e_dpb_dbg_f("curr %d update lt_idx to %d\n",
i, dpb->max_lt_idx);
}
}
h264e_dpb_dbg_f("curr %d ref_status 0x%03x count %d -> %d dist %d\n",
i, dpb->ref_sta[i], dpb->ref_cnt[i],
ref_idx, dpb->ref_dist[i]);
// update the reference frame status and counter only once
if (ref_idx == i)
continue;
dpb->ref_sta[ref_idx] |= REF_BY_REFR(i);
dpb->ref_cnt[ref_idx]++;
h264e_dpb_dbg_f("refr %d ref_status 0x%03x count %d\n",
ref_idx, dpb->ref_sta[ref_idx], dpb->ref_cnt[ref_idx]);
}
mpp_enc_put_hier_info(base);
if (hal_h264e_debug & H264E_DBG_DPB)
h264e_dpb_dump_hier(dpb);
return MPP_OK;
}
static void h264e_dpb_frm_swap(H264eDpb *dpb, RK_S32 a, RK_S32 b)
{
H264eDpbFrm tmp;
tmp = dpb->frames[a];
dpb->frames[a] = dpb->frames[b];
dpb->frames[b] = tmp;
}
H264eDpbFrm *h264e_dpb_get_curr(H264eDpb *dpb, RK_S32 new_seq)
{
RK_S32 gop_cnt = 0;
RK_S32 gop_idx = 0;
RK_S32 gop_idx_wrap = 0;
H264eDpbFrm *frm = &dpb->frames[dpb->curr_idx];
h264e_dpb_dbg_f("try get curr %d new_seq %d gop cnt %d idx %d\n",
dpb->seq_idx, new_seq, dpb->gop_cnt, dpb->gop_idx);
if (!frm->inited)
h264e_dpb_init_curr(dpb, frm);
mpp_assert(!frm->on_used);
mpp_assert(!dpb->curr);
if (new_seq) {
// NOTE: gop_idx here is for next gop_idx
dpb->gop_idx = 1;
dpb->gop_cnt = 0;
if (dpb->seq_idx)
dpb->seq_cnt++;
dpb->seq_idx = 0;
gop_cnt = 0;
gop_idx = 0;
} else {
gop_cnt = dpb->gop_cnt;
gop_idx = dpb->gop_idx++;
}
h264e_dpb_dbg_f("A frm cnt %d gop %d idx %d dpb gop %d idx %d\n",
frm->frm_cnt, gop_cnt, gop_idx,
dpb->gop_cnt, dpb->gop_idx);
if (dpb->gop_idx >= dpb->gop_len) {
dpb->gop_idx = 0;
dpb->gop_cnt++;
}
frm->frm_cnt = dpb->seq_idx++;
frm->gop_cnt = gop_cnt;
frm->gop_idx = gop_idx;
h264e_dpb_dbg_f("B frm cnt %d gop %d idx %d dpb gop %d idx %d\n",
frm->frm_cnt, gop_cnt, gop_idx,
dpb->gop_cnt, dpb->gop_idx);
gop_idx_wrap = gop_idx;
if (!gop_idx && gop_cnt)
gop_idx_wrap = dpb->gop_len;
frm->info = dpb->ref_inf[gop_idx_wrap];
frm->ref_status = dpb->ref_sta[gop_idx];
frm->ref_count = dpb->ref_cnt[gop_idx];
frm->ref_dist = dpb->ref_dist[gop_idx_wrap];
frm->poc = frm->frm_cnt * 2;
frm->lt_idx = frm->info.lt_idx;
frm->on_used = 1;
h264e_dpb_dbg_f("setup frm %d gop %d idx %d wrap %d ref dist %d\n",
frm->frm_cnt, frm->gop_cnt, frm->gop_idx, gop_idx_wrap, frm->ref_dist);
dpb->curr = frm;
h264e_dpb_dbg_f("frm %d old frm num %d next %d\n",
frm->frm_cnt, dpb->curr_frm_num, dpb->next_frm_num);
// new_seq is for dpb reset and IDR frame
if (new_seq) {
RK_S32 i;
frm->info.is_idr = 1;
frm->info.is_intra = 1;
// init to 0
dpb->curr_frm_num = 0;
dpb->next_frm_num = 1;
frm->frame_num = 0;
frm->poc = 0;
// mmco 5 mark all reference frame to be non-referenced
for (i = 0; i < dpb->curr_idx; i++) {
H264eDpbFrm *tmp = &dpb->frames[i];
tmp->on_used = 0;
tmp->info.is_non_ref = 1;
tmp->info.is_lt_ref = 0;
tmp->ref_status = 0;
tmp->ref_count = 0;
tmp->marked_unref = 0;
}
dpb->dpb_size = 0;
dpb->lt_size = 0;
dpb->st_size = 0;
dpb->unref_cnt = 0;
} else
dpb->curr_frm_num = dpb->next_frm_num;
frm->frame_num = dpb->curr_frm_num;
dpb->next_frm_num = dpb->curr_frm_num + !frm->info.is_non_ref;
h264e_dpb_dbg_f("frm %d new frm num %d next %d\n",
frm->frm_cnt, dpb->curr_frm_num, dpb->next_frm_num);
if (hal_h264e_debug & H264E_DBG_DPB)
h264e_dpb_dump_frms(dpb);
return frm;
}
H264eDpbFrm *h264e_dpb_get_refr(H264eDpbFrm *frm)
{
RK_S32 i;
H264eDpbFrm *ref = NULL;
H264eDpb *dpb = frm->dpb;
RK_S32 frm_cnt = frm->frm_cnt;
RK_S32 ref_dist = frm->ref_dist;
RK_S32 ref_frm_cnt = frm_cnt + ref_dist;
for (i = 0; i < dpb->curr_idx; i++) {
H264eDpbFrm *tmp = &dpb->frames[i];
if (tmp->on_used && !tmp->info.is_non_ref &&
tmp->frm_cnt == ref_frm_cnt) {
ref = &dpb->frames[i];
break;
}
}
h264e_dpb_dbg_f("frm %d found dist %d refer frm %d at %d %p\n",
frm_cnt, ref_dist, ref_frm_cnt, i, ref);
if (NULL == ref)
ref = &dpb->frames[dpb->curr_idx];
return ref;
}
static int cmp_st_list(const void *p0, const void *p1)
{
H264eDpbFrm *frm0 = *(H264eDpbFrm **)p0;
H264eDpbFrm *frm1 = *(H264eDpbFrm **)p1;
if (frm0->frame_num == frm1->frame_num)
return 0;
if (frm0->frame_num < frm1->frame_num)
return 1;
else
return -1;
}
static int cmp_lt_list(const void *p0, const void *p1)
{
H264eDpbFrm *frm0 = *(H264eDpbFrm **)p0;
H264eDpbFrm *frm1 = *(H264eDpbFrm **)p1;
if (frm0->lt_idx == frm1->lt_idx)
return 0;
if (frm0->lt_idx > frm1->lt_idx)
return 1;
else
return -1;
}
/*
* Build list function
*
* This function should build the default list for current frame.
* Then check the reference frame is the default one or not.
* Reorder command is need if the reference frame is not match.
*/
void h264e_dpb_build_list(H264eDpb *dpb)
{
RK_S32 i, j;
RK_S32 st_size = 0;
RK_S32 lt_size = 0;
if (dpb->curr->info.is_intra)
return ;
// init list
// 1. found all short term and long term ref
for (i = 0; i < dpb->curr_idx; i++) {
H264eDpbFrm *frm = &dpb->frames[i];
if (!frm->on_used)
continue;
if (frm->info.is_non_ref)
continue;
h264e_dpb_dbg_f("idx %d on_used %x ref_status %03x is_non_ref %d lt_ref %d\n",
i, frm->on_used, frm->ref_status,
frm->info.is_non_ref, frm->info.is_lt_ref);
if (!frm->info.is_non_ref) {
if (!frm->info.is_lt_ref) {
dpb->stref[st_size] = frm;
st_size++;
h264e_dpb_dbg_f("found st %d st_size %d %p\n", i, st_size, frm);
} else {
dpb->ltref[lt_size] = frm;
lt_size++;
h264e_dpb_dbg_f("found lt %d lt_size %d %p\n", i, lt_size, frm);
}
}
}
h264e_dpb_dbg_f("dpb_size %d st_size %d lt_size %d\n", dpb->dpb_size, st_size, lt_size);
// sort st list
if (st_size > 1) {
if (hal_h264e_debug & H264E_DBG_DPB) {
mpp_log_f("dpb st list before sort\n");
h264e_dpb_dump_listX(dpb->stref, st_size);
}
qsort(dpb->stref, st_size, sizeof(dpb->stref[0]), cmp_st_list);
if (hal_h264e_debug & H264E_DBG_DPB) {
mpp_log_f("dpb st list after sort\n");
h264e_dpb_dump_listX(dpb->stref, st_size);
}
}
if (lt_size > 1) {
if (hal_h264e_debug & H264E_DBG_DPB) {
mpp_log_f("dpb lt list before sort\n");
h264e_dpb_dump_listX(dpb->ltref, lt_size);
}
qsort(dpb->ltref, lt_size, sizeof(dpb->ltref[0]), cmp_lt_list);
if (hal_h264e_debug & H264E_DBG_DPB) {
mpp_log_f("dpb lt list after sort\n");
h264e_dpb_dump_listX(dpb->ltref, lt_size);
}
}
// generate list before reorder
memset(dpb->list, 0, sizeof(dpb->list));
j = 0;
for (i = 0; i < st_size; i++)
dpb->list[j++] = dpb->stref[i];
for (i = 0; i < lt_size; i++)
dpb->list[j++] = dpb->ltref[i];
dpb->st_size = st_size;
dpb->lt_size = lt_size;
mpp_assert(dpb->dpb_size == st_size + lt_size);
if (hal_h264e_debug & H264E_DBG_DPB)
h264e_dpb_dump_list(dpb);
if (dpb->st_size + dpb->lt_size) {
H264eDpbFrm *curr = dpb->curr;
H264eDpbFrm *def_ref = dpb->list[0];
RK_S32 curr_frm_cnt = curr->frm_cnt;
RK_S32 def_ref_frm_cnt = def_ref->frm_cnt;
RK_S32 set_ref_frm_cnt = curr->frm_cnt + curr->ref_dist;
dpb->need_reorder = (def_ref_frm_cnt != set_ref_frm_cnt) ? (1) : (0);
h264e_dpb_dbg_f("refer curr %d def %d set %d reorder %d\n",
curr_frm_cnt, def_ref_frm_cnt, set_ref_frm_cnt,
dpb->need_reorder);
} else {
h264e_dpb_dbg_f("refer NULL\n");
}
}
void h264e_dpb_build_marking(H264eDpb *dpb)
{
RK_S32 i;
H264eDpbFrm *frm = dpb->curr;
H264eDpbFrm *ref = h264e_dpb_get_refr(frm);
h264e_dpb_dbg_f("curr %d gop %d idx %d ref %d ready -> frm %d gop %d idx %d\n",
frm->frm_cnt, frm->gop_cnt, frm->gop_idx, !frm->info.is_non_ref,
ref->frm_cnt, ref->gop_cnt, ref->gop_cnt);
// refernce frame can not mark itself as unreferenced.
// So do NOT clear RECN flag here
// clear the ref status and count once
if (frm != ref) {
ref->ref_status &= ~(REF_BY_REFR(frm->gop_idx));
if (ref->ref_count > 0)
ref->ref_count--;
h264e_dpb_dbg_f("refr %d ref_status %03x count %d\n",
ref->gop_idx, ref->ref_status, ref->ref_count);
}
if (!frm->info.is_non_ref && frm->info.is_lt_ref) {
h264e_dpb_dbg_f("found lt idx %d curr max %d\n", frm->lt_idx, dpb->curr_max_lt_idx);
if (frm->lt_idx > dpb->curr_max_lt_idx) {
dpb->next_max_lt_idx = frm->lt_idx;
}
}
if (frm->info.is_idr)
return ;
if (frm->info.is_non_ref)
return ;
h264e_dpb_dbg_f("curr -- frm %d gop %d idx %d T%d\n",
frm->frm_cnt, frm->gop_cnt, frm->gop_idx, frm->info.temporal_id);
// if we are reference frame scan the previous frame to mark
for (i = 0; i < dpb->curr_idx; i++) {
H264eDpbFrm *tmp = &dpb->frames[i];
if (!tmp->on_used)
continue;
if (tmp->info.is_non_ref)
continue;
h264e_dpb_dbg_f("slot %2d frm %3d gop %3d idx %2d T%d lt %d cnt %d\n",
i, tmp->frm_cnt, tmp->gop_cnt, tmp->gop_idx,
tmp->info.temporal_id, tmp->info.is_lt_ref, tmp->ref_count);
if (tmp->info.is_lt_ref) {
if (frm->info.is_lt_ref && frm->lt_idx == tmp->lt_idx) {
h264e_dpb_dbg_f("frm %3d lt idx %d replace frm %d dpb size %d\n",
frm->frm_cnt, tmp->lt_idx, tmp->frm_cnt,
dpb->dpb_size);
}
continue;
}
if (!tmp->marked_unref && !tmp->ref_count &&
tmp != frm && tmp != ref &&
tmp->info.temporal_id == frm->info.temporal_id) {
/*
* NOTE: In ffmpeg we can not mark reference frame to be
* non-reference frame. But in JM it is valid for mmco execution
* is after frame decoding. So for compatibility consideration
* we do NOT remove current reference frame from dpb.
* That is the reason for frm->gop_index != ref_index
*
* There is a case for the first frame of a new gop which is not
* first frame of the whole sequeuce. On this case we need to
* remove frame in previous gop
*
* Tsvc temporal hierarchy dependency require the reference
* must be marked non-reference frame by the frame with same
* temporal layer id.
*/
dpb->unref[dpb->unref_cnt] = tmp;
dpb->unref_cnt++;
tmp->marked_unref = 1;
h264e_dpb_dbg_f("frm %d T%d mark frm %d gop %d idx %d to be unreference dpb size %d\n",
frm->frm_cnt, frm->info.temporal_id, tmp->frm_cnt, tmp->gop_cnt,
tmp->gop_idx, dpb->dpb_size);
}
}
h264e_dpb_dbg_f("dpb size %d unref_cnt %d\n", dpb->dpb_size, dpb->unref_cnt);
}
void h264e_dpb_curr_ready(H264eDpb *dpb)
{
H264eDpbFrm *frm = dpb->curr;
H264eDpbFrm *ref = h264e_dpb_get_refr(frm);
h264e_dpb_dbg_f("curr %d gop %d idx %d refr -> frm %d gop %d idx %d ready\n",
frm->frm_cnt, frm->gop_cnt, frm->gop_idx,
ref->frm_cnt, ref->gop_cnt, ref->gop_idx, frm->info.is_non_ref);
if (!frm->info.is_non_ref) {
frm->ref_status &= ~(REF_BY_RECN(frm->gop_idx));
frm->ref_count--;
}
if (!dpb->curr->info.is_non_ref) {
RK_S32 i;
RK_S32 insert = -1;
dpb->dpb_size++;
if (dpb->curr->info.is_lt_ref) {
// long-term ref swap and replace
for (i = dpb->max_st_cnt; i < dpb->curr_idx; i++) {
H264eDpbFrm *tmp = &dpb->frames[i];
// try found the swap frame with same lt_idx
if (!tmp->on_used) {
insert = i;
break;
} else {
if (tmp->lt_idx == frm->lt_idx) {
tmp->on_used = 0;
dpb->dpb_size--;
insert = i;
break;
}
}
}
} else {
// normal gop position swap and decrease ref_cnt
for (i = 0; i < dpb->max_st_cnt; i++) {
H264eDpbFrm *tmp = &dpb->frames[i];
if (!tmp->on_used) {
insert = i;
break;
}
}
}
mpp_assert(insert >= 0);
h264e_dpb_dbg_f("frm %d lt %d swap from %d to pos %d\n",
frm->frm_cnt, frm->info.is_lt_ref,
dpb->curr_idx, insert);
h264e_dpb_frm_swap(dpb, insert, dpb->curr_idx);
} else
dpb->curr->on_used = 0;
if (hal_h264e_debug & H264E_DBG_DPB)
h264e_dpb_dump_frms(dpb);
dpb->curr = NULL;
}

View File

@@ -1,665 +0,0 @@
/*
* 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 "h264e_slice"
#include <string.h>
#include "mpp_mem.h"
#include "mpp_bitread.h"
#include "hal_h264e_com.h"
#include "h264e_dpb.h"
#include "h264e_slice.h"
#include "h264e_stream.h"
#define RD_LOG(bit, log, val) \
do { \
h264e_dpb_slice("%4d bit rd %s %d\n", bit.used_bits, log, val); \
} while (0)
RK_S32 h264e_slice_read(H264eSlice *slice, void *p, RK_S32 size)
{
BitReadCtx_t bit;
RK_S32 ret = 0;
RK_S32 val = 0;
RK_S32 bit_cnt = 0;
mpp_set_bitread_ctx(&bit, p, size);
ret |= mpp_read_longbits(&bit, 32, (RK_U32 *)&val);
RD_LOG(bit, "start code", val);
ret |= mpp_read_bits(&bit, 1, &slice->forbidden_bit);
RD_LOG(bit, "forbidden_zero_bit", slice->forbidden_bit);
ret |= mpp_read_bits(&bit, 2, &slice->nal_reference_idc);
RD_LOG(bit, "nal_ref_idc", slice->nal_reference_idc);
ret |= mpp_read_bits(&bit, 5, &slice->nalu_type);
RD_LOG(bit, "nal_unit_type", slice->nalu_type);
ret = mpp_read_ue(&bit, &slice->start_mb_nr);
RD_LOG(bit, "first_mb_nr", slice->start_mb_nr);
ret |= mpp_read_ue(&bit, &slice->slice_type);
RD_LOG(bit, "slice_type", slice->slice_type);
ret |= mpp_read_ue(&bit, &slice->pic_parameter_set_id);
RD_LOG(bit, "pic_parameter_set_id", slice->pic_parameter_set_id);
ret |= mpp_read_bits(&bit, 16, &slice->frame_num);
RD_LOG(bit, "frame_num", slice->frame_num);
slice->idr_flag = (slice->nalu_type == 5);
if (slice->idr_flag) {
ret |= mpp_read_ue(&bit, &slice->idr_pic_id);
RD_LOG(bit, "idr_pic_id", slice->idr_pic_id);
}
// pic_order_cnt_type here
// vpu hardware is always zero. Just ignore
// NOTE: Only P slice has num_ref_idx_override flag and ref_pic_list_modification flag
if (slice->slice_type == 0) {
ret |= mpp_read_bits(&bit, 1, &slice->num_ref_idx_override);
RD_LOG(bit, "num_ref_idx_override", slice->num_ref_idx_override);
ret |= mpp_read_bits(&bit, 1, &slice->ref_pic_list_modification_flag);
RD_LOG(bit, "ref_pic_list_modification_flag",
slice->ref_pic_list_modification_flag);
}
// NOTE: hardware is always zero
slice->ref_pic_list_modification_flag = 0;
if (slice->nal_reference_idc) {
if (slice->idr_flag) {
ret |= mpp_read_bits(&bit, 1, &slice->no_output_of_prior_pics);
RD_LOG(bit, "no_output_of_prior_pics",
slice->no_output_of_prior_pics);
ret |= mpp_read_bits(&bit, 1, &slice->long_term_reference_flag);
RD_LOG(bit, "long_term_reference_flag",
slice->long_term_reference_flag);
} else {
ret |= mpp_read_bits(&bit, 1, &slice->adaptive_ref_pic_buffering);
RD_LOG(bit, "adaptive_ref_pic_buffering",
slice->adaptive_ref_pic_buffering);
mpp_assert(slice->adaptive_ref_pic_buffering == 0);
}
}
if (slice->entropy_coding_mode && slice->slice_type != H264_I_SLICE) {
ret |= mpp_read_ue(&bit, &slice->cabac_init_idc);
RD_LOG(bit, "cabac_init_idc", slice->cabac_init_idc);
}
ret |= mpp_read_se(&bit, &slice->qp_delta);
RD_LOG(bit, "qp_delta", slice->qp_delta);
ret |= mpp_read_ue(&bit, &slice->disable_deblocking_filter_idc);
RD_LOG(bit, "disable_deblocking_filter_idc",
slice->disable_deblocking_filter_idc);
ret |= mpp_read_se(&bit, &slice->slice_alpha_c0_offset_div2);
RD_LOG(bit, "slice_alpha_c0_offset_div2",
slice->slice_alpha_c0_offset_div2);
ret |= mpp_read_se(&bit, &slice->slice_beta_offset_div2);
RD_LOG(bit, "slice_beta_offset_div2", slice->slice_beta_offset_div2);
h264e_dpb_slice("non-aligned used bit %d\n", bit.used_bits);
if (slice->entropy_coding_mode) {
if (bit.num_remaining_bits_in_curr_byte_) {
RK_U32 tmp = bit.num_remaining_bits_in_curr_byte_;
ret |= mpp_read_bits(&bit, tmp, &val);
RD_LOG(bit, "cabac aligned bit", tmp);
}
}
bit_cnt = bit.used_bits;
h264e_dpb_slice("total aligned used bit %d\n", bit_cnt);
return bit_cnt;
}
#define WR_LOG(log, val) \
do { \
h264e_dpb_slice("B %2d b %d val %08x - %s %d\n", \
s->byte_cnt, s->buffered_bits, s->byte_buffer, \
log, val); \
} while (0)
RK_S32 h264e_slice_write(H264eSlice *slice, void *p, RK_U32 size)
{
H264eStream stream;
H264eStream *s = &stream;
RK_S32 i;
RK_S32 bitCnt = 0;
h264e_stream_init(s, p, size);
RK_U8 *tmp = (RK_U8 *)s->buffer;
/* nal header */
h264e_stream_put_bits(s, 0, 24, "start_code_zero");
h264e_stream_put_bits(s, 1, 8, "start_code_one");
WR_LOG("start_code", 1);
h264e_stream_put_bits(s, 0, 1, "forbidden_bit");
WR_LOG("forbidden_bit", 0);
h264e_stream_put_bits(s, slice->nal_reference_idc, 2, "nal_reference_idc");
WR_LOG("nal_reference_idc", slice->nal_reference_idc);
h264e_stream_put_bits(s, slice->nalu_type, 5, "nalu_type");
WR_LOG("nalu_type", slice->nalu_type);
/* slice header */
h264e_stream_write_ue(s, slice->start_mb_nr, "start_mb_nr");
WR_LOG("first_mb_nr", slice->start_mb_nr);
h264e_stream_write_ue(s, slice->slice_type, "slice_type");
WR_LOG("slice_type", slice->slice_type);
h264e_stream_write_ue(s, slice->pic_parameter_set_id, "pic_parameter_set_id");
WR_LOG("pic_parameter_set_id", slice->pic_parameter_set_id);
h264e_stream_put_bits_with_detect(s, slice->frame_num, 16, "frame_num");
WR_LOG("frame_num", slice->frame_num);
slice->idr_flag = (slice->nalu_type == 5);
if (slice->idr_flag) {
h264e_stream_write_ue(s, slice->idr_pic_id, "idr_pic_id");
WR_LOG("idr_pic_id", slice->idr_pic_id);
}
// Force to use poc type 0 here
{
RK_S32 pic_order_cnt_lsb = slice->pic_order_cnt_lsb;
RK_S32 max_poc_lsb = (1 << slice->log2_max_poc_lsb) - 1;
if (pic_order_cnt_lsb >= max_poc_lsb)
pic_order_cnt_lsb -= max_poc_lsb;
h264e_stream_put_bits_with_detect(s, pic_order_cnt_lsb, 16, "pic_order_cnt_lsb");
WR_LOG("pic_order_cnt_lsb", pic_order_cnt_lsb);
}
if (slice->slice_type == 0) {
h264e_stream_put_bits_with_detect(s, slice->num_ref_idx_override, 1,
"num_ref_idx_override");
WR_LOG("num_ref_idx_override", slice->num_ref_idx_override);
h264e_stream_put_bits_with_detect(s, slice->ref_pic_list_modification_flag, 1,
"ref_pic_list_reordering");
WR_LOG("ref_pic_list_reordering", slice->ref_pic_list_modification_flag);
}
if (slice->ref_pic_list_modification_flag) {
h264e_stream_write_ue(s, slice->modification_of_pic_nums_idc,
"modification_of_pic_nums_idc");
WR_LOG("modification_of_pic_nums_idc", slice->modification_of_pic_nums_idc);
switch (slice->modification_of_pic_nums_idc) {
case 0 :
case 1 : {
h264e_stream_write_ue(s, slice->abs_diff_pic_num_minus1,
"abs_diff_pic_num_minus1");
WR_LOG("abs_diff_pic_num_minus1", slice->abs_diff_pic_num_minus1);
} break;
case 2 : {
h264e_stream_write_ue(s, slice->long_term_pic_idx,
"long_term_pic_idx");
WR_LOG("long_term_pic_idx", slice->long_term_pic_idx);
} break;
default : {
mpp_err_f("invalid modification_of_pic_nums_idc %d\n",
slice->modification_of_pic_nums_idc);
} break;
}
h264e_stream_write_ue(s, 3,
"modification_of_pic_nums_idc");
WR_LOG("modification_of_pic_nums_idc", 3);
}
// NOTE: ignore nal ref idc here
h264e_dpb_mmco("nal_reference_idc %d idr_flag %d\n",
slice->nal_reference_idc, slice->idr_flag);
if (slice->nal_reference_idc) {
if (slice->idr_flag) {
h264e_stream_put_bits_with_detect(s, slice->no_output_of_prior_pics, 1,
"no_output_of_prior_pics_flag");
WR_LOG("no_output_of_prior_pics_flag", slice->no_output_of_prior_pics);
h264e_stream_put_bits_with_detect(s, slice->long_term_reference_flag, 1,
"long_term_reference_flag");
WR_LOG("long_term_reference_flag", slice->long_term_reference_flag);
// clear long_term_reference_flag flag
slice->long_term_reference_flag = 0;
} else {
h264e_dpb_mmco("mmco count %d\n", slice->mmco_cnt);
if (!list_empty(&slice->mmco)) {
H264eMmco *mmco, *n;
h264e_stream_put_bits_with_detect(s, 1, 1,
"adaptive_ref_pic_marking_mode_flag");
WR_LOG("adaptive_ref_pic_marking_mode_flag", 1);
list_for_each_entry_safe(mmco, n, &slice->mmco, H264eMmco, list) {
h264e_dpb_mmco("del mmco %p at %p list %p %p\n",
mmco, slice, mmco->list.prev, mmco->list.next);
list_del_init(&mmco->list);
h264e_stream_write_ue(s, mmco->mmco,
"memory_management_control_operation");
WR_LOG("memory_management_control_operation", mmco->mmco);
switch (mmco->mmco) {
case 1 : {
h264e_stream_write_ue(s, mmco->difference_of_pic_nums_minus1,
"difference_of_pic_nums_minus1");
WR_LOG("difference_of_pic_nums_minus1",
mmco->difference_of_pic_nums_minus1);
} break;
case 2 : {
h264e_stream_write_ue(s, mmco->long_term_pic_num ,
"long_term_pic_num");
WR_LOG("long_term_pic_num",
mmco->long_term_pic_num);
} break;
case 3 : {
h264e_stream_write_ue(s, mmco->difference_of_pic_nums_minus1,
"difference_of_pic_nums_minus1");
WR_LOG("difference_of_pic_nums_minus1",
mmco->difference_of_pic_nums_minus1);
h264e_stream_write_ue(s, mmco->long_term_frame_idx ,
"long_term_frame_idx");
WR_LOG("long_term_frame_idx", mmco->long_term_frame_idx);
} break;
case 4 : {
h264e_stream_write_ue(s, mmco->max_long_term_frame_idx_plus1,
"max_long_term_frame_idx_plus1");
WR_LOG("max_long_term_frame_idx_plus1",
mmco->max_long_term_frame_idx_plus1);
} break;
case 5 : {
} break;
case 6 : {
h264e_stream_write_ue(s, mmco->long_term_frame_idx,
"long_term_frame_idx");
WR_LOG("long_term_frame_idx", mmco->long_term_frame_idx);
} break;
default : {
mpp_err_f("invalid mmco %d\n", mmco->mmco);
} break;
}
h264e_dpb_mmco("free %p\n", mmco);
MPP_FREE(mmco);
slice->mmco_cnt--;
}
h264e_stream_write_ue(s, 0,
"memory_management_control_operation");
} else {
h264e_stream_put_bits_with_detect(s, 0, 1,
"adaptive_ref_pic_marking_mode_flag");
WR_LOG("adaptive_ref_pic_marking_mode_flag", 0);
}
mpp_assert(slice->mmco_cnt == 0);
}
}
if (slice->entropy_coding_mode && slice->slice_type != H264_I_SLICE) {
h264e_stream_write_ue(s, slice->cabac_init_idc, "cabac_init_idc");
WR_LOG("cabac_init_idc", slice->cabac_init_idc);
}
h264e_stream_write_se(s, slice->qp_delta, "qp_delta");
WR_LOG("qp_delta", slice->qp_delta);
h264e_stream_write_ue(s, 0, "disable_deblocking_filter_idc");
WR_LOG("disable_deblocking_filter_idc", slice->disable_deblocking_filter_idc);
h264e_stream_write_se(s, 0, "slice_alpha_c0_offset_div2");
WR_LOG("slice_alpha_c0_offset_div2", slice->slice_alpha_c0_offset_div2);
h264e_stream_write_se(s, 0, "slice_beta_offset_div2");
WR_LOG("slice_beta_offset_div2", slice->slice_beta_offset_div2);
bitCnt = s->buffered_bits + s->byte_cnt * 8;
if (s->buffered_bits) {
// NOTE: only have aligned bit on cabac mode but cavlc also need to write byte cache to memory
RK_S32 left = (8 - s->buffered_bits);
for (i = 0; i < left; i++) {
h264e_stream_put_bits_with_detect(s, 1, 1, "align_bit");
WR_LOG("align_bit", 1);
}
}
// update on cabac mode
if (slice->entropy_coding_mode)
bitCnt = s->buffered_bits + s->byte_cnt * 8;
WR_LOG("all done", 0);
RK_S32 pos = 0;
char log[256];
pos = sprintf(log + pos, "sw stream: ");
for (i = 0; i < 16; i ++) {
pos += sprintf(log + pos, "%02x ", tmp[i]);
}
pos += sprintf(log + pos, "\n");
h264e_dpb_slice(log);
return bitCnt;
}
H264eMmco *h264e_slice_gen_mmco(RK_S32 id, RK_S32 arg0, RK_S32 arg1)
{
H264eMmco *mmco = mpp_malloc(H264eMmco, 1);
if (NULL == mmco) {
mpp_err_f("failed to malloc mmco structure\n");
return NULL;
}
mmco->mmco = id;
switch (id) {
case 0 : {
} break;
case 1 : {
mmco->difference_of_pic_nums_minus1 = arg0;
} break;
case 2 : {
mmco->long_term_pic_num = arg0;
} break;
case 3 : {
mmco->difference_of_pic_nums_minus1 = arg0;
mmco->long_term_pic_num = arg1;
} break;
case 4 : {
mmco->max_long_term_frame_idx_plus1 = arg0;
} break;
case 5 : {
} break;
case 6 : {
mmco->long_term_frame_idx = arg0;
} break;
default : {
mpp_err_f("invalid mmco %d\n", id);
} break;
}
INIT_LIST_HEAD(&mmco->list);
h264e_dpb_mmco("gen mmco %p\n", mmco);
return mmco;
}
MPP_RET h264e_slice_add_mmco(H264eSlice *slice, H264eMmco *mmco)
{
list_add_tail(&mmco->list, &slice->mmco);
slice->mmco_cnt++;
h264e_dpb_mmco("add mmco %p to %p list %p %p\n",
mmco, slice, mmco->list.prev, mmco->list.next);
return MPP_OK;
}
MPP_RET h264e_slice_update(H264eSlice *slice, void *p)
{
H264eDpb *dpb = (H264eDpb *)p;
H264eDpbFrm *frm = &dpb->frames[dpb->curr_idx];
slice->nal_reference_idc = !frm->info.is_non_ref;
h264e_dpb_slice("gop %d nal_reference_idc %d is_non_ref %d\n",
frm->gop_idx, slice->nal_reference_idc,
frm->info.is_non_ref);
// update reorder according to current dpb status
if (dpb->need_reorder) {
H264eDpbFrm *ref = h264e_dpb_get_refr(frm);
h264e_dpb_slice("reorder to frm %d gop %d idx %d\n",
ref->frm_cnt, ref->gop_cnt, ref->gop_idx);
slice->ref_pic_list_modification_flag = 1;
mpp_assert(!ref->info.is_non_ref);
slice->modification_of_pic_nums_idc = (ref->info.is_lt_ref) ? (2) : (0);
if (ref->info.is_lt_ref) {
slice->modification_of_pic_nums_idc = 2;
slice->long_term_pic_idx = ref->lt_idx;
h264e_dpb_slice("reorder lt idx %d \n", slice->long_term_pic_idx);
} else {
/* Only support ref pic num less than current pic num case */
slice->modification_of_pic_nums_idc = 0;
slice->abs_diff_pic_num_minus1 = MPP_ABS(frm->frame_num - ref->frame_num) - 1;
h264e_dpb_slice("reorder st cur %d ref %d diff - 1 %d\n",
frm->frame_num, ref->frame_num,
slice->abs_diff_pic_num_minus1);
}
dpb->need_reorder = 0;
}
// remove frame if they are not used any more
// NOTE: only add marking on reference frame
INIT_LIST_HEAD(&slice->mmco);
slice->mmco_cnt = 0;
if (!frm->info.is_non_ref) {
H264eMmco *mmco = NULL;
if (frm->info.is_lt_ref) {
if (frm->info.is_idr) {
// IDR long-term is directly flag
slice->long_term_reference_flag = 1;
} else {
if (dpb->next_max_lt_idx != dpb->curr_max_lt_idx) {
RK_S32 max_lt_idx_p1 = dpb->next_max_lt_idx + 1;
mmco = h264e_slice_gen_mmco(4, max_lt_idx_p1, 0);
h264e_dpb_mmco("add mmco 4 %d\n", max_lt_idx_p1);
h264e_slice_add_mmco(slice, mmco);
dpb->curr_max_lt_idx = dpb->next_max_lt_idx;
}
mmco = h264e_slice_gen_mmco(6, frm->lt_idx, 0);
h264e_dpb_mmco("add mmco 6 %d\n", frm->lt_idx);
h264e_slice_add_mmco(slice, mmco);
}
}
if (dpb->unref_cnt) {
RK_U32 i = 0;
RK_S32 cur_frm_num = frm->frame_num;
for (i = 0; i < dpb->unref_cnt; i++) {
H264eDpbFrm *unref = dpb->unref[i];
RK_S32 unref_frm_num = unref->frame_num;
if (!unref->info.is_lt_ref) {
RK_S32 difference_of_pic_nums_minus1 = MPP_ABS(unref_frm_num - cur_frm_num) - 1;
h264e_dpb_mmco("cur_frm_num %d unref_frm_num %d\n", cur_frm_num, unref_frm_num);
h264e_dpb_mmco("add mmco st 1 %d\n", difference_of_pic_nums_minus1);
mmco = h264e_slice_gen_mmco(1, difference_of_pic_nums_minus1, 0);
} else {
h264e_dpb_mmco("add mmco lt 2 %d\n", unref->lt_idx);
mmco = h264e_slice_gen_mmco(2, unref->lt_idx, 0);
}
h264e_slice_add_mmco(slice, mmco);
/* update frame status here */
unref->marked_unref = 0;
unref->info.is_non_ref = 1;
unref->on_used = 0;
h264e_dpb_mmco("set frm %d gop %d idx %d to not used\n",
unref->frm_cnt, unref->gop_cnt, unref->gop_idx);
// decrease dpb size here for sometime frame will be remove later
dpb->dpb_size--;
}
dpb->unref_cnt = 0;
}
if (hal_h264e_debug & H264E_DBG_SLICE)
h264e_dpb_dump_frms(dpb);
}
return MPP_OK;
}
static RK_S32 frame_no = 0;
RK_S32 h264e_slice_move(RK_U8 *dst, RK_U8 *src, RK_S32 dst_bit, RK_S32 src_bit, RK_S32 src_size)
{
RK_S32 dst_byte = dst_bit / 8;
RK_S32 src_byte = src_bit / 8;
RK_S32 dst_bit_r = dst_bit & 7;
RK_S32 src_bit_r = src_bit & 7;
RK_S32 src_len = src_size - src_byte;
RK_S32 diff_len = 0;
if (src_bit_r == 0 && dst_bit_r == 0) {
// direct copy
if (hal_h264e_debug & H264E_DBG_SLICE)
mpp_log_f("direct copy %p -> %p %d\n", src, dst, src_len);
memcpy(dst + dst_byte, src + src_byte, src_len);
return diff_len;
}
RK_U8 *psrc = src + src_byte;
RK_U8 *pdst = dst + dst_byte;
RK_U16 tmp16a, tmp16b, tmp16c, last_tmp;
RK_U8 tmp0, tmp1;
RK_U32 loop = src_len;
RK_U32 i = 0;
RK_U32 src_zero_cnt = 0;
RK_U32 dst_zero_cnt = 0;
RK_U32 dst_len = 0;
if (hal_h264e_debug & H264E_DBG_SLICE)
mpp_log("bit [%d %d] [%d %d] loop %d\n", src_bit, dst_bit,
src_bit_r, dst_bit_r, loop);
last_tmp = pdst[0] >> (8 - dst_bit_r) << (8 - dst_bit_r);
for (i = 0; i < loop; i++) {
if (psrc[0] == 0) {
src_zero_cnt++;
} else {
src_zero_cnt = 0;
}
// tmp0 tmp1 is next two non-aligned bytes from src
tmp0 = psrc[0];
tmp1 = (i < loop - 1) ? psrc[1] : 0;
if (src_zero_cnt >= 2 && tmp1 == 3) {
if (hal_h264e_debug & H264E_DBG_SLICE)
mpp_log("found 03 at src pos %d %02x %02x %02x %02x %02x %02x %02x %02x\n",
i, psrc[-2], psrc[-1], psrc[0], psrc[1], psrc[2],
psrc[3], psrc[4], psrc[5]);
psrc++;
i++;
tmp1 = psrc[1];
src_zero_cnt = 0;
diff_len--;
}
// get U16 data
tmp16a = ((RK_U16)tmp0 << 8) | (RK_U16)tmp1;
if (src_bit_r) {
tmp16b = tmp16a << src_bit_r;
} else {
tmp16b = tmp16a;
}
if (dst_bit_r)
tmp16c = tmp16b >> dst_bit_r | (last_tmp >> (8 - dst_bit_r) << (16 - dst_bit_r));
else
tmp16c = tmp16b;
pdst[0] = (tmp16c >> 8) & 0xFF;
pdst[1] = tmp16c & 0xFF;
if (hal_h264e_debug & H264E_DBG_SLICE) {
if (i < 10) {
mpp_log("%03d src [%04x] -> [%04x] + last [%04x] -> %04x\n", i, tmp16a, tmp16b, last_tmp, tmp16c);
}
if (i >= loop - 10) {
mpp_log("%03d src [%04x] -> [%04x] + last [%04x] -> %04x\n", i, tmp16a, tmp16b, last_tmp, tmp16c);
}
}
if (dst_zero_cnt == 2 && pdst[0] <= 0x3) {
if (hal_h264e_debug & H264E_DBG_SLICE)
mpp_log("found 03 at dst frame %d pos %d\n", frame_no, dst_len);
pdst[2] = pdst[1];
pdst[1] = pdst[0];
pdst[0] = 0x3;
pdst++;
diff_len++;
dst_len++;
dst_zero_cnt = 0;
}
if (pdst[0] == 0)
dst_zero_cnt++;
else
dst_zero_cnt = 0;
last_tmp = tmp16c;
psrc++;
pdst++;
dst_len++;
}
frame_no++;
return diff_len;
}

View File

@@ -1,130 +0,0 @@
/*
* 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.
*/
#ifndef __H264E_SLICE_H__
#define __H264E_SLICE_H__
#include "rk_type.h"
#include "mpp_err.h"
#include "mpp_list.h"
/*
* For H.264 encoder slice header process.
* Remove some syntax that encoder not supported.
* Field, mbaff, B slice are not supported yet.
*/
#define MAX_H264E_REFS_CNT 8
typedef struct H264eMmco_t H264eMmco;
typedef struct H264eSlice_t H264eSlice;
typedef struct H264eMmco_t {
struct list_head list;
/*
* mmco (Memory management control operation) value
* 0 - End memory_management_control_operation syntax element loop
* 1 - Mark a short-term reference picture as "unused for reference"
* 2 - Mark a long-term reference picture as "unused for reference"
* 3 - Mark a short-term reference picture as "used for long-term
* reference" and assign a long-term frame index to it
* 4 - Specify the maximum long-term frame index and mark all long-term
* reference pictures having long-term frame indices greater than
* the maximum value as "unused for reference"
* 5 - Mark all reference pictures as "unused for reference" and set the
* MaxLongTermFrameIdx variable to "no long-term frame indices"
* 6 - Mark the current picture as "used for long-term reference" and
* assign a long-term frame index to it
*/
RK_S32 mmco;
RK_S32 difference_of_pic_nums_minus1; // for MMCO 1 & 3
RK_S32 long_term_pic_num; // for MMCO 2
RK_S32 long_term_frame_idx; // for MMCO 3 & 6
RK_S32 max_long_term_frame_idx_plus1; // for MMCO 4
} H264eMmco;
typedef struct H264eSlice_t {
/* Input parameter before reading */
RK_U32 max_num_ref_frames;
RK_U32 entropy_coding_mode;
RK_S32 log2_max_poc_lsb;
/* Nal parameters */
RK_S32 forbidden_bit;
RK_S32 nal_reference_idc;
RK_S32 nalu_type;
/* Unchanged parameters */
RK_U32 start_mb_nr;
RK_U32 slice_type;
RK_U32 pic_parameter_set_id;
RK_S32 frame_num;
RK_S32 num_ref_idx_override;
RK_S32 qp_delta;
RK_U32 cabac_init_idc;
RK_U32 disable_deblocking_filter_idc;
RK_S32 slice_alpha_c0_offset_div2;
RK_S32 slice_beta_offset_div2;
RK_S32 idr_flag;
RK_U32 idr_pic_id;
/* for poc mode 0 */
RK_S32 pic_order_cnt_lsb;
RK_S32 num_ref_idx_active;
/* idr mmco flag */
RK_S32 no_output_of_prior_pics;
RK_S32 long_term_reference_flag;
/* Changable parameters */
RK_S32 adaptive_ref_pic_buffering;
/* reorder parameter */
RK_S32 ref_pic_list_modification_flag;
RK_S32 modification_of_pic_nums_idc;
RK_S32 abs_diff_pic_num_minus1;
RK_S32 long_term_pic_idx;
RK_S32 abs_diff_view_idx_minus1;
/* mmco parameter */
struct list_head mmco;
RK_S32 mmco_cnt;
/* slice modification infomation */
void * hw_buf;
void * sw_buf;
RK_S32 hw_length;
RK_S32 sw_length;
} H264eSlice;
#ifdef __cplusplus
extern "C" {
#endif
RK_S32 h264e_slice_read(H264eSlice *slice, void *p, RK_S32 size);
RK_S32 h264e_slice_write(H264eSlice *slice, void *p, RK_U32 size);
RK_S32 h264e_slice_move(RK_U8 *dst, RK_U8 *src, RK_S32 dst_bit, RK_S32 src_bit,
RK_S32 src_size);
MPP_RET h264e_slice_update(H264eSlice *slice, void *p);
H264eMmco *h264e_slice_gen_mmco(RK_S32 id, RK_S32 arg0, RK_S32 arg1);
MPP_RET h264e_slice_add_mmco(H264eSlice *slice, H264eMmco *mmco);
#ifdef __cplusplus
}
#endif
#endif /* __H264E_SLICE_H__ */