diff options
author | Shivaansh Agrawal <Shivaansh.Agrawal@ittiam.com> | 2022-08-04 17:58:33 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-08-04 17:58:33 +0000 |
commit | bb777b6d5213b1106896f98376a262ce792b050c (patch) | |
tree | 0d2bac831c0736cf5773c3c9a6f9a18c5d8541ea | |
parent | ad4721e6e39d62d0c2d5d5283e31b8c9ef9cfca0 (diff) | |
parent | f6d36057aa46cdc01a74eb68469133b64b1773ca (diff) | |
download | libhevc-bb777b6d5213b1106896f98376a262ce792b050c.tar.gz |
Decoder: add support for QP and block_type map export in library am: f6dcd29208 am: b01b876d8d am: f6d36057aa
Original change: https://android-review.googlesource.com/c/platform/external/libhevc/+/1972341
Change-Id: Ief75d72fb9d7cd3f27ed5c33b86f8d9510c936ce
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rwxr-xr-x | FrameInfo.md | 21 | ||||
-rw-r--r-- | decoder/ihevcd_api.c | 38 | ||||
-rw-r--r-- | decoder/ihevcd_cxa.h | 87 | ||||
-rw-r--r-- | decoder/ihevcd_decode.c | 56 | ||||
-rw-r--r-- | decoder/ihevcd_defs.h | 5 | ||||
-rw-r--r-- | decoder/ihevcd_parse_headers.c | 1 | ||||
-rw-r--r-- | decoder/ihevcd_parse_slice.c | 28 | ||||
-rw-r--r-- | decoder/ihevcd_structs.h | 41 | ||||
-rwxr-xr-x | decoder/ihevcd_utils.c | 12 | ||||
-rw-r--r-- | fuzzer/hevc_dec_fuzzer.cpp | 32 | ||||
-rw-r--r-- | test/decoder/main.c | 196 |
11 files changed, 461 insertions, 56 deletions
diff --git a/FrameInfo.md b/FrameInfo.md new file mode 100755 index 0000000..618e1aa --- /dev/null +++ b/FrameInfo.md @@ -0,0 +1,21 @@ +## Frame Info exported from libHEVC + +### Introduction +QP and CU type maps for H265 are defined for each 8x8 coding unit. +The QP values defined as unsigned 8-bit numbers can range from <1, 51> and CU type can be +INTER/INTRA/SKIP. HEVC defines them in ihevc_defs.h as PRED_MODE_INTER = 0, PRED_MODE_INTRA = 1 +and PRED_MODE_SKIP = 2. +Set the “u4_frame_info_enable” flag to enable encoder/decoder to populate and return the qp values +and CU type data in its output structure ihevcd_cxa_video_decode_op_t via pu1_8x8_blk_qp_map and +pu1_8x8_blk_type_map. + +### Mapping to the frame +Within a video sequence, CTUs of a fixed size (16x16, 32x32, or 64x64) can be further divided into +CUs of size as low as 8x8 pixels. A CU’s number of QP entries (each for 8x8 blocks) can range from +1 to 64. A frame with a resolution of WdxHt has a total of (align8(Wd) x align8(Ht)) / 64 entries +for QP and CU type map each. Qp and CU type values for each 8x8 block are stored in raster scan +order. Refer to ihevcd_cxa.h for details. + +### Plugin/Application +The encoder/decoder keeps the QP and CU type map as a part of its output handle. The plugins can +access these data through the output structure. diff --git a/decoder/ihevcd_api.c b/decoder/ihevcd_api.c index 9bca829..031808d 100644 --- a/decoder/ihevcd_api.c +++ b/decoder/ihevcd_api.c @@ -438,6 +438,16 @@ static IV_API_CALL_STATUS_T api_check_struct_sanity(iv_obj_t *ps_handle, return (IV_FAIL); } + if(((codec_t *)(ps_handle->pv_codec_handle))->u1_enable_cu_info + && !ps_ip->pu1_8x8_blk_qp_map && !ps_ip->pu1_8x8_blk_type_map) + { + ps_op->s_ivd_video_decode_op_t.u4_error_code |= 1 + << IVD_UNSUPPORTEDPARAM; + ps_op->s_ivd_video_decode_op_t.u4_error_code |= + IHEVCD_FRAME_INFO_OP_BUF_NULL; + return (IV_FAIL); + } + } break; @@ -1196,6 +1206,11 @@ WORD32 ihevcd_allocate_static_bufs(iv_obj_t **pps_codec_obj, ps_codec->i4_share_disp_buf = 0; } + if (ps_create_ip->s_ivd_create_ip_t.u4_size == sizeof(ihevcd_cxa_create_ip_t)) + { + ps_codec->u1_enable_cu_info = ps_create_ip->u4_enable_frame_info; + } + ps_codec->e_chroma_fmt = ps_create_ip->s_ivd_create_ip_t.e_output_format; ps_codec->pf_aligned_alloc = pf_aligned_alloc; @@ -1906,7 +1921,7 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec) qp_const_flag_size /= 8; /* QP changes at CU level - So store at 8x8 level */ - num_8x8 = (ht * wd) / (MIN_CU_SIZE * MIN_CU_SIZE); + num_8x8 = (wd * ht) / (MIN_CU_SIZE * MIN_CU_SIZE); qp_size = num_8x8; /* To hold vertical boundary strength */ @@ -2019,6 +2034,22 @@ WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec) memset(pv_buf, 0, size); ps_codec->pv_tu_data = pv_buf; + /* CU info map to store qp and CU type at 8x8 level */ + if(ps_codec->u1_enable_cu_info) + { + size = ((wd * ht) / (MIN_CU_SIZE * MIN_CU_SIZE)) * BUF_MGR_MAX_CNT; + + pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size); + RETURN_IF((NULL == pv_buf), IV_FAIL); + memset(pv_buf, 0, size); + ps_codec->pu1_qp_map_base = pv_buf; + + pv_buf = ps_codec->pf_aligned_alloc(pv_mem_ctxt, 128, size); + RETURN_IF((NULL == pv_buf), IV_FAIL); + memset(pv_buf, 0, size); + ps_codec->pu1_cu_type_map_base = pv_buf; + } + { sps_t *ps_sps = (ps_codec->s_parse.ps_sps_base + ps_codec->i4_sps_id); @@ -2141,6 +2172,11 @@ WORD32 ihevcd_free_dynamic_bufs(codec_t *ps_codec) ALIGNED_FREE(ps_codec, ps_codec->pv_mv_bank_buf_base); ALIGNED_FREE(ps_codec, ps_codec->pu1_ref_pic_buf_base); ALIGNED_FREE(ps_codec, ps_codec->pu1_cur_chroma_ref_buf); + if(ps_codec->u1_enable_cu_info) + { + ALIGNED_FREE(ps_codec, ps_codec->pu1_qp_map_base); + ALIGNED_FREE(ps_codec, ps_codec->pu1_cu_type_map_base); + } ps_codec->u4_allocate_dynamic_done = 0; return IV_SUCCESS; diff --git a/decoder/ihevcd_cxa.h b/decoder/ihevcd_cxa.h index f81a7eb..7baf480 100644 --- a/decoder/ihevcd_cxa.h +++ b/decoder/ihevcd_cxa.h @@ -130,6 +130,16 @@ typedef enum { IHEVCD_UNSUPPORTED_CHROMA_FMT_IDC, /** + * Frame info output buffer null + */ + IHEVCD_FRAME_INFO_OP_BUF_NULL, + + /** + * Frame info insufficient buffer + */ + IHEVCD_INSUFFICIENT_METADATA_BUFFER, + + /** * Generic failure */ IHEVCD_FAIL = 0x7FFFFFFF @@ -161,6 +171,11 @@ typedef struct { typedef struct { ivd_create_ip_t s_ivd_create_ip_t; + + /** + * enable_frm_info + */ + UWORD32 u4_enable_frame_info; }ihevcd_cxa_create_ip_t; @@ -178,8 +193,60 @@ typedef struct { * ivd_video_decode_ip_t */ ivd_video_decode_ip_t s_ivd_video_decode_ip_t; + + /** + * 8x8 block QP map + */ + UWORD8 *pu1_8x8_blk_qp_map; + + /** + * 8x8 block type map + */ + UWORD8 *pu1_8x8_blk_type_map; + + /** + * 8x8 block QP map size + */ + UWORD32 u4_8x8_blk_qp_map_size; + + /** + * 8x8 block type map size + */ + UWORD32 u4_8x8_blk_type_map_size; }ihevcd_cxa_video_decode_ip_t; +/*********************************************************************************/ +/* QP and CU/Block type maps are defined for each 8x8 coding unit. */ +/* QP can range from <1, 51> and block type can be INTER/INTRA/SKIP. */ +/* */ +/* A frame with a resolution of WdxHt has a total of */ +/* (align8(Wd) x align8(Ht)) / 64 entries for QP and Block type map each. */ +/* */ +/* For example, for a frame of size 60x60 shown in the figure down, both */ +/* maps (QP and Block type) have the same layout. */ +/* Each block represents an 8x8 sub-block. Both width and height are aligned to */ +/* next largest multiple of 8, 64 in this case. */ +/* */ +/* 0 8 16 24 32 40 48 56 64 */ +/* 0 ------------------------------------------------ */ +/* | 0th | 1st | 2nd | 3rd | 4th | 5th | 6th | 7th | */ +/* 8 ------------------------------------------------ */ +/* | 8th | 9th | 10th | - | - | - | - | - | */ +/* 16 ------------------------------------------------ */ +/* | - | - | - | - | - | - | - | - | */ +/* 24 ------------------------------------------------ */ +/* | - | - | - | - | - | - | - | - | */ +/* 32 ------------------------------------------------ */ +/* | - | - | - | - | - | - | - | - | */ +/* 40 ------------------------------------------------ */ +/* | - | - | - | - | - | - | - | - | */ +/* 48 ------------------------------------------------ */ +/* | - | - | - | - | - | - | - | - | */ +/* 56 ------------------------------------------------ */ +/* | - | - | - | - | - | - | - | - | */ +/* 64 ------------------------------------------------ */ +/* */ +/*********************************************************************************/ typedef struct { @@ -187,6 +254,26 @@ typedef struct { * ivd_video_decode_op_t */ ivd_video_decode_op_t s_ivd_video_decode_op_t; + + /** + * 8x8 block QP map + */ + UWORD8 *pu1_8x8_blk_qp_map; + + /** + * 8x8 block type map + */ + UWORD8 *pu1_8x8_blk_type_map; + + /** + * 8x8 block QP map size + */ + UWORD32 u4_8x8_blk_qp_map_size; + + /** + * 8x8 block type map size + */ + UWORD32 u4_8x8_blk_type_map_size; }ihevcd_cxa_video_decode_op_t; diff --git a/decoder/ihevcd_decode.c b/decoder/ihevcd_decode.c index 4eed26c..d9ee1c0 100644 --- a/decoder/ihevcd_decode.c +++ b/decoder/ihevcd_decode.c @@ -363,6 +363,47 @@ static void ihevcd_fill_outargs(codec_t *ps_codec, ps_codec->i4_flush_mode = 0; } + if(ps_codec->u1_enable_cu_info && ps_dec_op->u4_output_present) + { + WORD32 info_map_dst_strd = ALIGN8(ps_codec->i4_wd) >> 3; + WORD32 info_map_src_strd = ALIGN64(ps_codec->i4_wd) >> 3; + WORD32 info_map_ht = ALIGN8(ps_codec->i4_ht); + UWORD32 info_map_size = (ALIGN8(ps_codec->i4_wd) * info_map_ht) >> 6; + WORD32 vert_8x8; + UWORD8 *pu1_out_qp_map, *pu1_qp_map; + UWORD8 *pu1_out_blk_type_map, *pu1_type_map; + + if(ps_hevcd_dec_ip->pu1_8x8_blk_qp_map) + { + ps_hevcd_dec_op->pu1_8x8_blk_qp_map = ps_hevcd_dec_ip->pu1_8x8_blk_qp_map; + ps_hevcd_dec_op->u4_8x8_blk_qp_map_size = info_map_size; + + pu1_out_qp_map = ps_hevcd_dec_op->pu1_8x8_blk_qp_map; + pu1_qp_map = ps_codec->as_buf_id_info_map[ps_codec->i4_disp_buf_id].pu1_qp_map; + for(vert_8x8 = 0; vert_8x8 < info_map_ht; vert_8x8++) + { + memcpy(pu1_out_qp_map, pu1_qp_map, info_map_dst_strd); + pu1_out_qp_map += info_map_dst_strd; + pu1_qp_map += info_map_src_strd; + } + } + + if(ps_hevcd_dec_ip->pu1_8x8_blk_type_map) + { + ps_hevcd_dec_op->pu1_8x8_blk_type_map = ps_hevcd_dec_ip->pu1_8x8_blk_type_map; + ps_hevcd_dec_op->u4_8x8_blk_type_map_size = info_map_size; + + pu1_out_blk_type_map = ps_hevcd_dec_op->pu1_8x8_blk_type_map; + pu1_type_map = + ps_codec->as_buf_id_info_map[ps_codec->i4_disp_buf_id].pu1_cu_type_map; + for(vert_8x8 = 0; vert_8x8 < info_map_ht; vert_8x8++) + { + memcpy(pu1_out_blk_type_map, pu1_type_map, info_map_dst_strd); + pu1_out_blk_type_map += info_map_dst_strd; + pu1_type_map += info_map_src_strd; + } + } + } } /** @@ -440,6 +481,21 @@ WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op) return IV_FAIL; } + if(ps_codec->u1_enable_cu_info && ps_codec->i4_sps_done) + { + UWORD32 blk_qp_map_size = ps_hevcd_dec_ip->u4_8x8_blk_qp_map_size; + UWORD32 blk_type_map_size = ps_hevcd_dec_ip->u4_8x8_blk_type_map_size; + UWORD32 blk_8x8_map_size = (ALIGN8(ps_codec->i4_wd) * ALIGN8(ps_codec->i4_ht)) >> 6; + + if ((ps_hevcd_dec_ip->pu1_8x8_blk_qp_map && blk_qp_map_size < blk_8x8_map_size) || + (ps_hevcd_dec_ip->pu1_8x8_blk_type_map && blk_type_map_size < blk_8x8_map_size)) + { + ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM; + ps_dec_op->u4_error_code |= IHEVCD_INSUFFICIENT_METADATA_BUFFER; + return IV_FAIL; + } + } + /* If reset flag is set, flush the existing buffers */ if(ps_codec->i4_reset_flag) { diff --git a/decoder/ihevcd_defs.h b/decoder/ihevcd_defs.h index 0dea27c..47fff65 100644 --- a/decoder/ihevcd_defs.h +++ b/decoder/ihevcd_defs.h @@ -102,6 +102,11 @@ */ #define MAX_REF_CNT 32 +/** + * Maximum number of CU info buffers + */ +#define MAX_CU_INFO_BUF_CNT MAX_REF_CNT + /*****************************************************************************/ /* Num cores releated defs */ /*****************************************************************************/ diff --git a/decoder/ihevcd_parse_headers.c b/decoder/ihevcd_parse_headers.c index f70e150..0ce1b27 100644 --- a/decoder/ihevcd_parse_headers.c +++ b/decoder/ihevcd_parse_headers.c @@ -1943,6 +1943,7 @@ IHEVCD_ERROR_T ihevcd_parse_sps(codec_t *ps_codec) ps_codec->i4_wd = ps_sps->i2_pic_width_in_luma_samples; ps_codec->i4_ht = ps_sps->i2_pic_height_in_luma_samples; + ps_codec->u4_num_8x8_blks = ALIGN64(ps_codec->i4_wd) * ALIGN64(ps_codec->i4_ht) >> 6; { WORD32 ref_strd; diff --git a/decoder/ihevcd_parse_slice.c b/decoder/ihevcd_parse_slice.c index a3e1e69..d6f74f9 100644 --- a/decoder/ihevcd_parse_slice.c +++ b/decoder/ihevcd_parse_slice.c @@ -1851,6 +1851,7 @@ IHEVCD_ERROR_T ihevcd_parse_coding_quadtree(codec_t *ps_codec, } else { + WORD32 qp = ps_codec->s_parse.u4_qp; /* Set current group QP if current CU is aligned with the group */ { WORD32 cu_pos_x = ps_codec->s_parse.s_cu.i4_pos_x << 3; @@ -1880,7 +1881,6 @@ IHEVCD_ERROR_T ihevcd_parse_coding_quadtree(codec_t *ps_codec, WORD32 qpg_x; WORD32 qpg_y; WORD32 i, j; - WORD32 qp; WORD32 cur_cu_offset; tu_t *ps_tu = ps_codec->s_parse.ps_tu; WORD32 cb_size = 1 << ps_codec->s_parse.s_cu.i4_log2_cb_size; @@ -1942,6 +1942,32 @@ IHEVCD_ERROR_T ihevcd_parse_coding_quadtree(codec_t *ps_codec, } } + /* Populate CU_info maps for current CU*/ + if(ps_codec->u1_enable_cu_info) + { + WORD32 cu_info_map_stride = ALIGN64(ps_codec->i4_wd) >> 3; + UWORD8 num_8x8_blks = 1 << (log2_cb_size - 3); + WORD32 vert_8x8, horz_8x8; + UWORD8 *pu1_cur_cu_type_map = + ps_codec->as_buf_id_info_map[ps_codec->as_process[0]. + i4_cur_pic_buf_id].pu1_cu_type_map; + UWORD8 *pu1_cur_qp_map = + ps_codec->as_buf_id_info_map[ps_codec->as_process[0].i4_cur_pic_buf_id].pu1_qp_map; + UWORD8 *pu1_cur_type_cu = pu1_cur_cu_type_map + (x0 >> 3) + + (y0 >> 3) * cu_info_map_stride; + UWORD8 *pu1_cur_qp_cu = pu1_cur_qp_map + (x0 >> 3) + + (y0 >> 3) * cu_info_map_stride; + for(vert_8x8 = 0; vert_8x8 < num_8x8_blks; vert_8x8++) + { + for(horz_8x8 = 0; horz_8x8 < num_8x8_blks; horz_8x8++) + { + pu1_cur_qp_cu[horz_8x8] = qp; + pu1_cur_type_cu[horz_8x8] = ps_codec->s_parse.s_cu.i4_pred_mode; + } + pu1_cur_qp_cu += cu_info_map_stride; + pu1_cur_type_cu += cu_info_map_stride; + } + } } diff --git a/decoder/ihevcd_structs.h b/decoder/ihevcd_structs.h index 407818a..cbc86af 100644 --- a/decoder/ihevcd_structs.h +++ b/decoder/ihevcd_structs.h @@ -1556,6 +1556,22 @@ typedef struct WORD32 i4_nctb; }process_ctxt_t; +/** + * Reference mapping from pic_buf_id to pointers to corresponding qp_map and CU_type_map + */ +typedef struct +{ + /** + * qp_map buffer + */ + UWORD8 *pu1_qp_map; + + /** + * CU_type buffer + */ + UWORD8 *pu1_cu_type_map; +}ref_map_t; + typedef void (*pf_inter_pred)(void *, void *, WORD32, @@ -2006,6 +2022,31 @@ struct _codec_t UWORD32 u4_ts; /** + * Enable CU_info + */ + UWORD8 u1_enable_cu_info; + + /** + * Ref mapping from pic_buf_id to corresponding CU_info maps + */ + ref_map_t as_buf_id_info_map[MAX_CU_INFO_BUF_CNT]; + + /** + * Total no of 8x8 blocks in luma samples + */ + WORD32 u4_num_8x8_blks; + + /** + * Pointer to base of qp_map buffer array + */ + UWORD8 *pu1_qp_map_base; + + /** + * Pointer to base of CU_type_map buffer array + */ + UWORD8 *pu1_cu_type_map_base; + + /** * Pointer to base of Video parameter set structure array */ vps_t *ps_vps_base; diff --git a/decoder/ihevcd_utils.c b/decoder/ihevcd_utils.c index b914a9b..563d948 100755 --- a/decoder/ihevcd_utils.c +++ b/decoder/ihevcd_utils.c @@ -1265,6 +1265,18 @@ IHEVCD_ERROR_T ihevcd_parse_pic_init(codec_t *ps_codec) } } + if(ps_codec->u1_enable_cu_info) + { + ps_codec->as_buf_id_info_map[cur_pic_buf_id].pu1_qp_map = + ps_codec->pu1_qp_map_base + (cur_pic_buf_id * ps_codec->u4_num_8x8_blks); + ps_codec->as_buf_id_info_map[cur_pic_buf_id].pu1_cu_type_map = + ps_codec->pu1_cu_type_map_base + (cur_pic_buf_id * ps_codec->u4_num_8x8_blks); + memset(ps_codec->as_buf_id_info_map[cur_pic_buf_id].pu1_qp_map, + 0, ps_codec->u4_num_8x8_blks); + memset(ps_codec->as_buf_id_info_map[cur_pic_buf_id].pu1_qp_map, + 0, ps_codec->u4_num_8x8_blks); + } + ps_codec->s_parse.s_deblk_ctxt.pu1_cur_pic_luma = pu1_cur_pic_luma; ps_codec->s_parse.s_deblk_ctxt.pu1_cur_pic_chroma = pu1_cur_pic_chroma; diff --git a/fuzzer/hevc_dec_fuzzer.cpp b/fuzzer/hevc_dec_fuzzer.cpp index 5561bb1..8dec5da 100644 --- a/fuzzer/hevc_dec_fuzzer.cpp +++ b/fuzzer/hevc_dec_fuzzer.cpp @@ -111,8 +111,8 @@ Codec::~Codec() {} void Codec::createCodec() { IV_API_CALL_STATUS_T ret; - ihevcd_cxa_create_ip_t create_ip; - ihevcd_cxa_create_op_t create_op; + ihevcd_cxa_create_ip_t create_ip{}; + ihevcd_cxa_create_op_t create_op{}; void *fxns = (void *)&ivd_api_function; create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; @@ -134,8 +134,8 @@ void Codec::createCodec() { } void Codec::deleteCodec() { - ivd_delete_ip_t delete_ip; - ivd_delete_op_t delete_op; + ivd_delete_ip_t delete_ip{}; + ivd_delete_op_t delete_op{}; delete_ip.e_cmd = IVD_CMD_DELETE; delete_ip.u4_size = sizeof(ivd_delete_ip_t); @@ -145,8 +145,8 @@ void Codec::deleteCodec() { } void Codec::resetCodec() { - ivd_ctl_reset_ip_t s_ctl_ip; - ivd_ctl_reset_op_t s_ctl_op; + ivd_ctl_reset_ip_t s_ctl_ip{}; + ivd_ctl_reset_op_t s_ctl_op{}; s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; @@ -157,8 +157,8 @@ void Codec::resetCodec() { } void Codec::setCores() { - ihevcd_cxa_ctl_set_num_cores_ip_t s_ctl_ip; - ihevcd_cxa_ctl_set_num_cores_op_t s_ctl_op; + ihevcd_cxa_ctl_set_num_cores_ip_t s_ctl_ip{}; + ihevcd_cxa_ctl_set_num_cores_op_t s_ctl_op{}; s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; s_ctl_ip.e_sub_cmd = @@ -171,8 +171,8 @@ void Codec::setCores() { } void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) { - ivd_ctl_set_config_ip_t s_ctl_ip; - ivd_ctl_set_config_op_t s_ctl_op; + ivd_ctl_set_config_ip_t s_ctl_ip{}; + ivd_ctl_set_config_op_t s_ctl_op{}; s_ctl_ip.u4_disp_wd = 0; s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; @@ -187,8 +187,8 @@ void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) { } void Codec::setArchitecture(IVD_ARCH_T arch) { - ihevcd_cxa_ctl_set_processor_ip_t s_ctl_ip; - ihevcd_cxa_ctl_set_processor_op_t s_ctl_op; + ihevcd_cxa_ctl_set_processor_ip_t s_ctl_ip{}; + ihevcd_cxa_ctl_set_processor_op_t s_ctl_op{}; s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; s_ctl_ip.e_sub_cmd = @@ -258,8 +258,8 @@ void Codec::decodeHeader(const uint8_t *data, size_t size) { while (size > 0) { IV_API_CALL_STATUS_T ret; - ivd_video_decode_ip_t dec_ip; - ivd_video_decode_op_t dec_op; + ivd_video_decode_ip_t dec_ip{}; + ivd_video_decode_op_t dec_op{}; size_t bytes_consumed; memset(&dec_ip, 0, sizeof(dec_ip)); @@ -300,8 +300,8 @@ void Codec::decodeHeader(const uint8_t *data, size_t size) { IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size, size_t *bytesConsumed) { IV_API_CALL_STATUS_T ret; - ivd_video_decode_ip_t dec_ip; - ivd_video_decode_op_t dec_op; + ivd_video_decode_ip_t dec_ip{}; + ivd_video_decode_op_t dec_op{}; memset(&dec_ip, 0, sizeof(dec_ip)); memset(&dec_op, 0, sizeof(dec_op)); diff --git a/test/decoder/main.c b/test/decoder/main.c index e274fba..421f81f 100644 --- a/test/decoder/main.c +++ b/test/decoder/main.c @@ -175,6 +175,7 @@ typedef struct { UWORD32 u4_piclen_flag; UWORD32 u4_file_save_flag; + UWORD32 u4_frame_info_enable; UWORD32 u4_chksum_save_flag; UWORD32 u4_max_frm_ts; IV_COLOR_FORMAT_T e_output_chroma_format; @@ -198,6 +199,8 @@ typedef struct CHAR ac_piclen_fname[STRLENGTH]; CHAR ac_ip_fname[STRLENGTH]; CHAR ac_op_fname[STRLENGTH]; + CHAR ac_qp_map_fname[STRLENGTH]; + CHAR ac_blk_type_map_fname[STRLENGTH]; CHAR ac_op_chksum_fname[STRLENGTH]; ivd_out_bufdesc_t s_disp_buffers[MAX_DISP_BUFFERS]; iv_yuv_buf_t s_disp_frm_queue[MAX_DISP_BUFFERS]; @@ -250,8 +253,11 @@ typedef enum VERSION, INPUT_FILE, OUTPUT, + QP_MAP_FILE, + BLK_TYPE_MAP_FILE, CHKSUM, SAVE_OUTPUT, + SAVE_FRAME_INFO, SAVE_CHKSUM, CHROMA_FORMAT, NUM_FRAMES, @@ -294,6 +300,10 @@ static const argument_t argument_mapping[] = "Input file\n" }, { "-o", "--output", OUTPUT, "Output file\n" }, + { "--", "--qp_map_file", QP_MAP_FILE, + "QP map file\n\n" }, + { "--", "--blk_type_map_file", BLK_TYPE_MAP_FILE, + "Block Type Map file\n" }, { "--", "--piclen", PICLEN, "Flag to signal if the decoder has to use a file containing number of bytes in each picture to be fed in each call\n" }, { "--", "--piclen_file", PICLEN_FILE, @@ -302,6 +312,8 @@ static const argument_t argument_mapping[] = "Output MD5 Checksum file\n" }, { "-s", "--save_output", SAVE_OUTPUT, "Save Output file\n" }, + { "--", "--save_frame_info", SAVE_FRAME_INFO, + "Enable frame_info\n" }, { "--", "--save_chksum", SAVE_CHKSUM, "Save Check sum file\n" }, { "--", "--chroma_format", CHROMA_FORMAT, @@ -866,12 +878,16 @@ void codec_exit(CHAR *pc_err_message) /*****************************************************************************/ void dump_output(vid_dec_ctx_t *ps_app_ctx, iv_yuv_buf_t *ps_disp_frm_buf, + ihevcd_cxa_video_decode_op_t *ps_hevcd_decode_op, UWORD32 u4_disp_frm_id, FILE *ps_op_file, + FILE *ps_qp_file, + FILE *ps_cu_type_file, FILE *ps_op_chksum_file, WORD32 i4_op_frm_ts, UWORD32 file_save, - UWORD32 chksum_save) + UWORD32 chksum_save, + UWORD32 cu_info_save) { @@ -918,9 +934,26 @@ void dump_output(vid_dec_ctx_t *ps_app_ctx, release_disp_frame(ps_app_ctx->cocodec_obj, u4_disp_id); - if(0 == file_save && 0 == chksum_save) + if(0 == file_save && 0 == chksum_save && 0 == cu_info_save) return; + if(0 != cu_info_save) + { + UWORD8 *buf; + if(ps_hevcd_decode_op->pu1_8x8_blk_qp_map && ps_qp_file) + { + buf = ps_hevcd_decode_op->pu1_8x8_blk_qp_map; + fwrite(buf, 1, ps_hevcd_decode_op->u4_8x8_blk_qp_map_size, ps_qp_file); + fflush(ps_qp_file); + } + if(ps_hevcd_decode_op->pu1_8x8_blk_type_map && ps_cu_type_file) + { + buf = ps_hevcd_decode_op->pu1_8x8_blk_type_map; + fwrite(buf, 1, ps_hevcd_decode_op->u4_8x8_blk_type_map_size, ps_cu_type_file); + fflush(ps_cu_type_file); + } + } + if(NULL == s_dump_disp_frm_buf.pv_y_buf) return; @@ -1162,22 +1195,34 @@ void parse_argument(vid_dec_ctx_t *ps_app_ctx, CHAR *argument, CHAR *value) case VERSION: break; case INPUT_FILE: - sscanf(value, "%s", ps_app_ctx->ac_ip_fname); + snprintf(value, STRLENGTH, "%s", ps_app_ctx->ac_ip_fname); //input_passed = 1; break; case OUTPUT: - sscanf(value, "%s", ps_app_ctx->ac_op_fname); + snprintf(value, STRLENGTH, "%s", ps_app_ctx->ac_op_fname); + break; + + case QP_MAP_FILE: + snprintf(value, STRLENGTH, "%s", ps_app_ctx->ac_qp_map_fname); + break; + + case BLK_TYPE_MAP_FILE: + snprintf(value, STRLENGTH, "%s", ps_app_ctx->ac_blk_type_map_fname); break; case CHKSUM: - sscanf(value, "%s", ps_app_ctx->ac_op_chksum_fname); + snprintf(value, STRLENGTH, "%s", ps_app_ctx->ac_op_chksum_fname); break; case SAVE_OUTPUT: sscanf(value, "%d", &ps_app_ctx->u4_file_save_flag); break; + case SAVE_FRAME_INFO: + sscanf(value, "%d", &ps_app_ctx->u4_frame_info_enable); + break; + case SAVE_CHKSUM: sscanf(value, "%d", &ps_app_ctx->u4_chksum_save_flag); break; @@ -1287,7 +1332,7 @@ void parse_argument(vid_dec_ctx_t *ps_app_ctx, CHAR *argument, CHAR *value) break; case PICLEN_FILE: - sscanf(value, "%s", ps_app_ctx->ac_piclen_fname); + snprintf(value, STRLENGTH, "%s", ps_app_ctx->ac_piclen_fname); break; case INVALID: @@ -1596,6 +1641,10 @@ void flush_output(iv_obj_t *codec_obj, UWORD8 *pu1_bs_buf, UWORD32 *pu4_op_frm_ts, FILE *ps_op_file, + FILE *ps_qp_file, + FILE *ps_cu_type_file, + UWORD8 *pu1_qp_map_buf, + UWORD8 *pu1_blk_type_map_buf, FILE *ps_op_chksum_file, UWORD32 u4_ip_frm_ts, UWORD32 u4_bytes_remaining) @@ -1654,6 +1703,12 @@ void flush_output(iv_obj_t *codec_obj, ps_out_buf->u4_num_bufs; ps_video_decode_op->u4_size = sizeof(ihevcd_cxa_video_decode_op_t); + s_hevcd_video_decode_ip.pu1_8x8_blk_qp_map = pu1_qp_map_buf; + s_hevcd_video_decode_ip.pu1_8x8_blk_type_map = pu1_blk_type_map_buf; + s_hevcd_video_decode_ip.u4_8x8_blk_qp_map_size = + (ADAPTIVE_MAX_HT * ADAPTIVE_MAX_WD) >> 6; + s_hevcd_video_decode_ip.u4_8x8_blk_type_map_size = + (ADAPTIVE_MAX_HT * ADAPTIVE_MAX_WD) >> 6; /*****************************************************************************/ /* API Call: Video Decode */ @@ -1664,10 +1719,10 @@ void flush_output(iv_obj_t *codec_obj, if(1 == ps_video_decode_op->u4_output_present) { dump_output(ps_app_ctx, &(ps_video_decode_op->s_disp_frm_buf), - ps_video_decode_op->u4_disp_buf_id, ps_op_file, - ps_op_chksum_file, + &s_hevcd_video_decode_op, ps_video_decode_op->u4_disp_buf_id, + ps_op_file, ps_qp_file, ps_cu_type_file, ps_op_chksum_file, *pu4_op_frm_ts, ps_app_ctx->u4_file_save_flag, - ps_app_ctx->u4_chksum_save_flag); + ps_app_ctx->u4_chksum_save_flag, ps_app_ctx->u4_frame_info_enable); (*pu4_op_frm_ts)++; } @@ -1729,6 +1784,8 @@ int main(WORD32 argc, CHAR *argv[]) FILE *ps_piclen_file = NULL; FILE *ps_ip_file = NULL; FILE *ps_op_file = NULL; + FILE *ps_qp_file = NULL; + FILE *ps_cu_type_file = NULL; FILE *ps_op_chksum_file = NULL; WORD32 ret; CHAR ac_error_str[STRLENGTH]; @@ -1746,6 +1803,8 @@ int main(WORD32 argc, CHAR *argv[]) UWORD32 u4_ip_buf_len; UWORD32 frm_cnt = 0; WORD32 total_bytes_comsumed; + UWORD8 *pu1_qp_map_buf = NULL; + UWORD8 *pu1_blk_type_map_buf = NULL; #ifdef PROFILE_ENABLE UWORD32 u4_tot_cycles = 0; @@ -1819,6 +1878,7 @@ int main(WORD32 argc, CHAR *argv[]) s_app_ctx.display = 0; s_app_ctx.full_screen = 0; s_app_ctx.u4_piclen_flag = 0; + s_app_ctx.u4_frame_info_enable = 0; s_app_ctx.fps = DEFAULT_FPS; file_pos = 0; total_bytes_comsumed = 0; @@ -1904,11 +1964,12 @@ int main(WORD32 argc, CHAR *argv[]) { if(CONFIG == get_argument(argv[i])) { - strcpy(ac_cfg_fname, argv[i + 1]); + strncpy(ac_cfg_fname, argv[i + 1], STRLENGTH); + ac_cfg_fname[STRLENGTH - 1] = '\0'; if((fp_cfg_file = fopen(ac_cfg_fname, "r")) == NULL) { - sprintf(ac_error_str, "Could not open Configuration file %s", - ac_cfg_fname); + snprintf(ac_error_str, sizeof(ac_error_str), + "Could not open Configuration file %s", ac_cfg_fname); codec_exit(ac_error_str); } read_cfg_file(&s_app_ctx, fp_cfg_file); @@ -1924,7 +1985,7 @@ int main(WORD32 argc, CHAR *argv[]) { if((fp_cfg_file = fopen(ac_cfg_fname, "r")) == NULL) { - sprintf(ac_error_str, "Could not open Configuration file %s", + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open Configuration file %s", ac_cfg_fname); codec_exit(ac_error_str); } @@ -1932,10 +1993,10 @@ int main(WORD32 argc, CHAR *argv[]) fclose(fp_cfg_file); } #else - sprintf(filename_with_path, "%s/%s", homedir, ac_cfg_fname); + snprintf(filename_with_path, sizeof(filename_with_path), "%s/%s", homedir, ac_cfg_fname); if((fp_cfg_file = fopen(filename_with_path, "r")) == NULL) { - sprintf(ac_error_str, "Could not open Configuration file %s", + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open Configuration file %s", ac_cfg_fname); codec_exit(ac_error_str); @@ -1968,19 +2029,24 @@ int main(WORD32 argc, CHAR *argv[]) exit(-1); } + if(1 == s_app_ctx.u4_frame_info_enable) + { + pu1_qp_map_buf = calloc(ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT >> 6, 1); + pu1_blk_type_map_buf = calloc(ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT >> 6, 1); + } /***********************************************************************/ /* create the file object for input file */ /***********************************************************************/ #ifdef IOS - sprintf(filename_with_path, "%s/%s", homedir, s_app_ctx.ac_ip_fname); + snprintf(filename_with_path, sizeof(filename_with_path), "%s/%s", homedir, s_app_ctx.ac_ip_fname); ps_ip_file = fopen(filename_with_path, "rb"); #else ps_ip_file = fopen(s_app_ctx.ac_ip_fname, "rb"); #endif if(NULL == ps_ip_file) { - sprintf(ac_error_str, "Could not open input file %s", + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open input file %s", s_app_ctx.ac_ip_fname); codec_exit(ac_error_str); } @@ -1990,14 +2056,14 @@ int main(WORD32 argc, CHAR *argv[]) if(1 == s_app_ctx.u4_piclen_flag) { #ifdef IOS - sprintf(filename_with_path, "%s/%s", homedir, s_app_ctx.ac_piclen_fname); + snprintf(filename_with_path, sizeof(filename_with_path), "%s/%s", homedir, s_app_ctx.ac_piclen_fname); ps_piclen_file = fopen(filename_with_path, "rb"); #else ps_piclen_file = fopen(s_app_ctx.ac_piclen_fname, "rb"); #endif if(NULL == ps_piclen_file) { - sprintf(ac_error_str, "Could not open piclen file %s", + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open piclen file %s", s_app_ctx.ac_piclen_fname); codec_exit(ac_error_str); } @@ -2009,7 +2075,7 @@ int main(WORD32 argc, CHAR *argv[]) if(1 == s_app_ctx.u4_file_save_flag) { #ifdef IOS - sprintf(filename_with_path, "%s/%s", documentdir, s_app_ctx.ac_op_fname); + snprintf(filename_with_path, sizeof(filename_with_path), "%s/%s", documentdir, s_app_ctx.ac_op_fname); ps_op_file = fopen(filename_with_path, "wb"); #else ps_op_file = fopen(s_app_ctx.ac_op_fname, "wb"); @@ -2017,26 +2083,52 @@ int main(WORD32 argc, CHAR *argv[]) if(NULL == ps_op_file) { - sprintf(ac_error_str, "Could not open output file %s", + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open output file %s", s_app_ctx.ac_op_fname); codec_exit(ac_error_str); } } /***********************************************************************/ + /* create the file object for cuinfo file */ + /***********************************************************************/ + if(1 == s_app_ctx.u4_frame_info_enable) + { +#ifdef IOS + snprintf(filename_with_path, sizeof(filename_with_path), "%s/%s", documentdir, s_app_ctx.ac_qp_map_fname); + ps_qp_file = fopen(filename_with_path, "wb"); + + snprintf(filename_with_path, sizeof(filename_with_path), "%s/%s", documentdir, s_app_ctx.ac_blk_type_map_fname); + ps_cu_type_file = fopen(filename_with_path, "wb"); +#else + ps_qp_file = fopen(s_app_ctx.ac_qp_map_fname, "wb"); + ps_cu_type_file = fopen(s_app_ctx.ac_blk_type_map_fname, "wb"); +#endif + + if(NULL == ps_qp_file) + { + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open output file %s", s_app_ctx.ac_qp_map_fname); + } + if(NULL == ps_cu_type_file) + { + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open output file %s", s_app_ctx.ac_blk_type_map_fname); + } + } + + /***********************************************************************/ /* create the file object for check sum file */ /***********************************************************************/ if(1 == s_app_ctx.u4_chksum_save_flag) { #if IOS - sprintf(filename_with_path, "%s/%s", documentdir, s_app_ctx.ac_op_chksum_fname); + snprintf(filename_with_path, sizeof(filename_with_path), "%s/%s", documentdir, s_app_ctx.ac_op_chksum_fname); ps_op_chksum_file = fopen(filename_with_path, "wb"); #else ps_op_chksum_file = fopen(s_app_ctx.ac_op_chksum_fname, "wb"); #endif if(NULL == ps_op_chksum_file) { - sprintf(ac_error_str, "Could not open check sum file %s", + snprintf(ac_error_str, sizeof(ac_error_str), "Could not open check sum file %s", s_app_ctx.ac_op_chksum_fname); codec_exit(ac_error_str); } @@ -2064,6 +2156,7 @@ int main(WORD32 argc, CHAR *argv[]) s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL; s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ihevcd_cxa_create_ip_t); s_create_op.s_ivd_create_op_t.u4_size = sizeof(ihevcd_cxa_create_op_t); + s_create_ip.u4_enable_frame_info = s_app_ctx.u4_frame_info_enable; @@ -2132,10 +2225,10 @@ int main(WORD32 argc, CHAR *argv[]) } - flush_output(codec_obj, &s_app_ctx, ps_out_buf, - pu1_bs_buf, &u4_op_frm_ts, - ps_op_file, ps_op_chksum_file, - u4_ip_frm_ts, u4_bytes_remaining); + flush_output(codec_obj, &s_app_ctx, ps_out_buf, pu1_bs_buf, &u4_op_frm_ts, + ps_op_file, ps_qp_file, ps_cu_type_file, + pu1_qp_map_buf, pu1_blk_type_map_buf, + ps_op_chksum_file, u4_ip_frm_ts, u4_bytes_remaining); /*****************************************************************************/ /* Decode header to get width and height and buffer sizes */ @@ -2223,6 +2316,12 @@ int main(WORD32 argc, CHAR *argv[]) ps_video_decode_ip->u4_size = sizeof(ihevcd_cxa_video_decode_ip_t); ps_video_decode_op->u4_size = sizeof(ihevcd_cxa_video_decode_op_t); + s_hevcd_video_decode_ip.pu1_8x8_blk_qp_map = pu1_qp_map_buf; + s_hevcd_video_decode_ip.pu1_8x8_blk_type_map = pu1_blk_type_map_buf; + s_hevcd_video_decode_ip.u4_8x8_blk_qp_map_size = + (ADAPTIVE_MAX_HT * ADAPTIVE_MAX_WD) >> 6; + s_hevcd_video_decode_ip.u4_8x8_blk_type_map_size = + (ADAPTIVE_MAX_HT * ADAPTIVE_MAX_WD) >> 6; /*****************************************************************************/ /* API Call: Header Decode */ @@ -2744,6 +2843,12 @@ int main(WORD32 argc, CHAR *argv[]) ps_out_buf->u4_num_bufs; ps_video_decode_op->u4_size = sizeof(ihevcd_cxa_video_decode_op_t); + s_hevcd_video_decode_ip.pu1_8x8_blk_qp_map = pu1_qp_map_buf; + s_hevcd_video_decode_ip.pu1_8x8_blk_type_map = pu1_blk_type_map_buf; + s_hevcd_video_decode_ip.u4_8x8_blk_qp_map_size = + (ADAPTIVE_MAX_HT * ADAPTIVE_MAX_WD) >> 6; + s_hevcd_video_decode_ip.u4_8x8_blk_type_map_size = + (ADAPTIVE_MAX_HT * ADAPTIVE_MAX_WD) >> 6; /* Get display buffer pointers */ if(1 == s_app_ctx.display) @@ -2826,10 +2931,10 @@ int main(WORD32 argc, CHAR *argv[]) ivd_ctl_reset_ip_t s_ctl_ip; ivd_ctl_reset_op_t s_ctl_op; - flush_output(codec_obj, &s_app_ctx, ps_out_buf, - pu1_bs_buf, &u4_op_frm_ts, - ps_op_file, ps_op_chksum_file, - u4_ip_frm_ts, u4_bytes_remaining); + flush_output(codec_obj, &s_app_ctx, ps_out_buf, pu1_bs_buf, &u4_op_frm_ts, + ps_op_file, ps_qp_file, ps_cu_type_file, + pu1_qp_map_buf, pu1_blk_type_map_buf, + ps_op_chksum_file, u4_ip_frm_ts, u4_bytes_remaining); s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; @@ -2941,10 +3046,10 @@ int main(WORD32 argc, CHAR *argv[]) width = ps_video_decode_op->s_disp_frm_buf.u4_y_wd; height = ps_video_decode_op->s_disp_frm_buf.u4_y_ht; dump_output(&s_app_ctx, &(ps_video_decode_op->s_disp_frm_buf), - ps_video_decode_op->u4_disp_buf_id, - ps_op_file, ps_op_chksum_file, + &s_hevcd_video_decode_op, ps_video_decode_op->u4_disp_buf_id, + ps_op_file, ps_qp_file, ps_cu_type_file, ps_op_chksum_file, u4_op_frm_ts, s_app_ctx.u4_file_save_flag, - s_app_ctx.u4_chksum_save_flag); + s_app_ctx.u4_chksum_save_flag, s_app_ctx.u4_frame_info_enable); u4_op_frm_ts++; } @@ -2963,10 +3068,11 @@ int main(WORD32 argc, CHAR *argv[]) /***********************************************************************/ /* To get the last decoded frames, call process with NULL input */ /***********************************************************************/ - flush_output(codec_obj, &s_app_ctx, ps_out_buf, - pu1_bs_buf, &u4_op_frm_ts, - ps_op_file, ps_op_chksum_file, - u4_ip_frm_ts, u4_bytes_remaining); + flush_output(codec_obj, &s_app_ctx, ps_out_buf, pu1_bs_buf, &u4_op_frm_ts, + ps_op_file, ps_qp_file, ps_cu_type_file, + pu1_qp_map_buf, pu1_blk_type_map_buf, + ps_op_chksum_file, u4_ip_frm_ts, u4_bytes_remaining); + /* set disp_end flag */ s_app_ctx.quit = 1; @@ -3039,6 +3145,13 @@ int main(WORD32 argc, CHAR *argv[]) { fclose(ps_op_chksum_file); } + if(1 == s_app_ctx.u4_frame_info_enable) + { + if(NULL != ps_qp_file) + fclose(ps_qp_file); + if(NULL != ps_cu_type_file) + fclose(ps_cu_type_file); + } } @@ -3054,6 +3167,13 @@ int main(WORD32 argc, CHAR *argv[]) free(ps_out_buf); free(pu1_bs_buf); + if(1 == s_app_ctx.u4_frame_info_enable) + { + if(pu1_qp_map_buf) + free(pu1_qp_map_buf); + if(pu1_blk_type_map_buf) + free(pu1_blk_type_map_buf); + } if(s_app_ctx.display_thread_handle) free(s_app_ctx.display_thread_handle); |