/* * Copyright 2021 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 "mpi_rc_test" #include #include #include "rk_mpi.h" #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_time.h" #include "mpp_common.h" #include "mpi_dec_utils.h" #include "mpi_enc_utils.h" #define MPI_BIT_DEPTH 8 #define MPI_PIXEL_MAX ((1 << MPI_BIT_DEPTH) - 1) typedef RK_U8 pixel; typedef struct { double psnr_y; double ssim_y; RK_U32 avg_bitrate; // Every sequence, byte per second RK_U32 ins_bitrate; // Every second, byte per second RK_U32 frame_size; // Every frame, byte } MpiRcStat; typedef struct { FILE *fp_input; FILE *fp_enc_out; FILE *fp_stat; } MpiRcFile; typedef struct { MpiEncTestArgs* enc_cmd; MpiRcStat stat; MpiRcFile file; RK_U8 *com_buf; MppCtx enc_ctx; MppCtx dec_ctx_post; MppCtx dec_ctx_pre; MppApi *enc_mpi; MppApi *dec_mpi_post; MppApi *dec_mpi_pre; /* 1. pre-decoder data */ FileReader reader; MppCodingType dec_type; RK_S32 pre_pkt_idx; RK_S32 pre_frm_idx; RK_S32 pre_frm_num; MppPacket dec_pkt_pre; RK_U8 *dec_in_buf_pre; RK_U32 dec_in_buf_pre_size; /* 2. encoder data */ MppBufferGroup pkt_grp; MppBuffer enc_pkt_buf; MppPacket enc_pkt; MppEncRcCfg rc_cfg; MppEncPrepCfg prep_cfg; MppTask enc_in_task; MppTask enc_out_task; /* 3. post-decoder data */ MppPacket dec_pkt_post; RK_U8 *dec_in_buf_post; RK_U32 dec_in_buf_post_size; RK_U32 loop_end; RK_U32 pkt_eos; RK_S32 frm_eos; RK_U32 enc_pkt_eos; MppEncCfg cfg; RK_S32 frm_idx; RK_U64 total_bits; double total_psnrs; double total_ssims; RK_U32 calc_base_idx; RK_U32 stream_size_1s; pthread_t dec_thr; RK_S64 start_enc; } MpiRc2TestCtx; static void mpi_rc_deinit(MpiRc2TestCtx *ctx) { MpiRcFile *file = &ctx->file; if (file->fp_enc_out) { fclose(file->fp_enc_out); file->fp_enc_out = NULL; } if (file->fp_stat) { fclose(file->fp_stat); file->fp_stat = NULL; } if (file->fp_input) { fclose(file->fp_input); file->fp_input = NULL; } if (ctx->reader) { reader_deinit(ctx->reader); ctx->reader = NULL; } MPP_FREE(ctx->com_buf); } static MPP_RET mpi_rc_init(MpiRc2TestCtx *ctx) { MpiEncTestArgs* enc_cmd = ctx->enc_cmd; if (enc_cmd->file_input) reader_init(&ctx->reader, enc_cmd->file_input, enc_cmd->type_src); if (NULL == ctx->reader) { mpp_err("failed to open dec input file %s\n", enc_cmd->file_input); return MPP_NOK; } mpp_log("input file %s size %ld\n", enc_cmd->file_input, reader_size(ctx->reader)); ctx->dec_type = enc_cmd->type_src; if (enc_cmd->file_output) { MpiRcFile *file = &ctx->file; file->fp_enc_out = fopen(enc_cmd->file_output, "w+b"); if (NULL == file->fp_enc_out) { mpp_err("failed to open enc output file %s\n", enc_cmd->file_output); return MPP_ERR_OPEN_FILE; } } return MPP_OK; } static MPP_RET mpi_rc_cmp_frame(MppFrame frame_in, MppFrame frame_out) { void *enc_buf = mpp_buffer_get_ptr(mpp_frame_get_buffer(frame_in)); void *dec_buf = mpp_buffer_get_ptr(mpp_frame_get_buffer(frame_out)); RK_U32 enc_width = mpp_frame_get_width(frame_in); RK_U32 enc_height = mpp_frame_get_height(frame_in); RK_U32 dec_width = mpp_frame_get_width(frame_out); RK_U32 dec_height = mpp_frame_get_height(frame_out); if (!enc_buf) { mpp_err_f("enc buf is NULL"); return MPP_NOK; } if (!dec_buf) { mpp_err_f("dec buf is NULL"); return MPP_NOK; } if (enc_width != dec_width) { mpp_err_f("enc_width %d != dec_width %d", enc_width, dec_width); return MPP_NOK; } if (enc_height != dec_height) { mpp_err_f("enc_height %d != dec_height %d", enc_height, dec_height); return MPP_NOK; } return MPP_OK; } static void mpi_rc_calc_psnr(MpiRcStat *stat, MppFrame frame_in, MppFrame frame_out) { RK_U32 x, y; RK_S32 tmp; double ssd_y = 0.0; double mse_y = 0.0; double psnr_y = 0.0; RK_U32 width = mpp_frame_get_width(frame_in); RK_U32 height = mpp_frame_get_height(frame_in); RK_U32 luma_size = width * height; RK_U32 enc_hor_stride = mpp_frame_get_hor_stride(frame_in); RK_U32 dec_hor_stride = mpp_frame_get_hor_stride(frame_out); RK_U8 *enc_buf = (RK_U8 *)mpp_buffer_get_ptr(mpp_frame_get_buffer(frame_in)); RK_U8 *dec_buf = (RK_U8 *)mpp_buffer_get_ptr(mpp_frame_get_buffer(frame_out)); RK_U8 *enc_buf_y = enc_buf; RK_U8 *dec_buf_y = dec_buf; for (y = 0 ; y < height; y++) { for (x = 0; x < width; x++) { tmp = enc_buf_y[x + y * enc_hor_stride] - dec_buf_y[x + y * dec_hor_stride]; tmp *= tmp; ssd_y += tmp; } } // NOTE: should be 65025.0 rather than 65025, // because 65025*luma_size may exceed // 1 << 32. mse_y = ssd_y / (65025.0 * luma_size); // 65025=255*255 if (mse_y <= 0.0000000001) psnr_y = 100; else psnr_y = -10.0 * log10f(mse_y); stat->psnr_y = psnr_y; } static float ssim_end1( int s1, int s2, int ss, int s12 ) { /* * Maximum value for 10-bit is: ss*64 = (2^10-1)^2*16*4*64 = 4286582784, * which will overflow in some cases. * s1*s1, s2*s2, and s1*s2 also obtain this value for edge cases: * ((2^10-1)*16*4)^2 = 4286582784. * Maximum value for 9-bit is: ss*64 = (2^9-1)^2*16*4*64 = 1069551616, * which will not overflow. */ static const int ssim_c1 = (int)(.01 * .01 * MPI_PIXEL_MAX * MPI_PIXEL_MAX * 64 + .5); static const int ssim_c2 = (int)(.03 * .03 * MPI_PIXEL_MAX * MPI_PIXEL_MAX * 64 * 63 + .5); int fs1 = s1; int fs2 = s2; int fss = ss; int fs12 = s12; int vars = fss * 64 - fs1 * fs1 - fs2 * fs2; int covar = fs12 * 64 - fs1 * fs2; return (float)(2 * fs1 * fs2 + ssim_c1) * (float)(2 * covar + ssim_c2) / ((float)(fs1 * fs1 + fs2 * fs2 + ssim_c1) * (float)(vars + ssim_c2)); } static float ssim_end4( int sum0[5][4], int sum1[5][4], int width ) { double ssim = 0.0; int i = 0; for (i = 0; i < width; i++ ) ssim += ssim_end1(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0], sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1], sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2], sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3] ); return ssim; } static void ssim_4x4x2_core( const pixel *pix1, intptr_t stride1, const pixel *pix2, intptr_t stride2, int sums[2][4] ) { int a = 0; int b = 0; int x = 0; int y = 0; int z = 0; for (z = 0; z < 2; z++ ) { uint32_t s1 = 0, s2 = 0, ss = 0, s12 = 0; for (y = 0; y < 4; y++ ) for ( x = 0; x < 4; x++ ) { a = pix1[x + y * stride1]; b = pix2[x + y * stride2]; s1 += a; s2 += b; ss += a * a; ss += b * b; s12 += a * b; } sums[z][0] = s1; sums[z][1] = s2; sums[z][2] = ss; sums[z][3] = s12; pix1 += 4; pix2 += 4; } } static float calc_ssim(pixel *pix1, RK_U32 stride1, pixel *pix2, RK_U32 stride2, int width, int height, void *buf, int *cnt) { int x = 0; int y = 0; int z = 0; float ssim = 0.0; int (*sum0)[4] = buf; int (*sum1)[4] = sum0 + (width >> 2) + 3; width >>= 2; height >>= 2; for ( y = 1; y < height; y++ ) { for ( ; z <= y; z++ ) { MPP_SWAP( void*, sum0, sum1 ); for ( x = 0; x < width; x += 2 ) ssim_4x4x2_core(&pix1[4 * (x + z * stride1)], stride1, &pix2[4 * (x + z * stride2)], stride2, &sum0[x] ); } for ( x = 0; x < width - 1; x += 4 ) ssim += ssim_end4(sum0 + x, sum1 + x, MPP_MIN(4, width - x - 1)); } *cnt = (height - 1) * (width - 1); return ssim; } static void mpi_rc_calc_ssim(MpiRc2TestCtx *ctx, MppFrame frame_in, MppFrame frame_out) { int cnt = 0; float ssim = 0; MpiRcStat *stat = &ctx->stat; RK_U32 width = mpp_frame_get_width(frame_in); RK_U32 height = mpp_frame_get_height(frame_in); RK_U32 enc_hor_stride = mpp_frame_get_hor_stride(frame_in); RK_U32 dec_hor_stride = mpp_frame_get_hor_stride(frame_out); pixel *enc_buf = (RK_U8 *)mpp_buffer_get_ptr(mpp_frame_get_buffer(frame_in)); pixel *dec_buf = (RK_U8 *)mpp_buffer_get_ptr(mpp_frame_get_buffer(frame_out)); pixel *enc_buf_y = enc_buf; pixel *dec_buf_y = dec_buf; if (NULL == ctx->com_buf) ctx->com_buf = mpp_malloc(RK_U8, enc_hor_stride * mpp_frame_get_ver_stride(frame_out) * 2); ssim = calc_ssim(enc_buf_y, enc_hor_stride, dec_buf_y, dec_hor_stride, width - 2, height - 2, ctx->com_buf, &cnt); ssim /= (float)cnt; stat->ssim_y = (double)ssim; } static MPP_RET mpi_rc_calc_stat(MpiRc2TestCtx *ctx, MppFrame frame_in, MppFrame frame_out) { MPP_RET ret = MPP_OK; MpiRcStat *stat = &ctx->stat; ret = mpi_rc_cmp_frame(frame_in, frame_out); if (ret) { mpp_err_f("mpi_rc_cmp_frame failed ret %d", ret); return MPP_NOK; } if (ctx->enc_cmd->psnr_en) { mpi_rc_calc_psnr(stat, frame_in, frame_out); ctx->total_psnrs += stat->psnr_y; } if (ctx->enc_cmd->ssim_en) { mpi_rc_calc_ssim(ctx, frame_in, frame_out); ctx->total_ssims += stat->ssim_y; } return ret; } static void mpi_rc_log_stat(MpiRc2TestCtx *ctx, RK_U32 frame_count, RK_U32 one_second, RK_U32 seq_end) { //static char rc_log_str[1024] = {0}; MpiRcStat *stat = &ctx->stat; MpiRcFile *file = &ctx->file; FILE *fp = file->fp_stat; mpp_log("frame %3d | frame_size %6d bytes | psnr %5.2f | ssim %5.5f", frame_count, stat->frame_size, stat->psnr_y, stat->ssim_y); if (one_second) mpp_log("ins_bitrate %f kbps", stat->ins_bitrate * 8.0 / 1000); if (fp) { fprintf(fp, "%3d,%6d,%5.2f,%5.5f,", frame_count, stat->frame_size, stat->psnr_y, stat->ssim_y); if (one_second) fprintf(fp, "bitsrate: %d,", stat->ins_bitrate); if (!seq_end) fprintf(fp, "\n"); } } static MPP_RET mpi_rc_enc_init(MpiRc2TestCtx *ctx) { MpiEncTestArgs* enc_cmd = ctx->enc_cmd; MppApi *enc_mpi = NULL; MppCtx enc_ctx = NULL; MppPollType block = MPP_POLL_NON_BLOCK; MppEncRcCfg *rc_cfg = &ctx->rc_cfg; MppEncSeiMode sei_mode = MPP_ENC_SEI_MODE_ONE_SEQ; MppEncCfg cfg = ctx->cfg; RK_U32 debreath_en = 0; RK_U32 debreath_s = 0; MPP_RET ret = MPP_OK; // encoder init ret = mpp_create(&ctx->enc_ctx, &ctx->enc_mpi); if (ret) { mpp_err("mpp_create encoder failed\n"); goto MPP_TEST_OUT; } enc_mpi = ctx->enc_mpi; enc_ctx = ctx->enc_ctx; rc_cfg->fps_in_denorm = 1; rc_cfg->fps_out_denorm = 1; rc_cfg->fps_in_num = 30; rc_cfg->fps_out_num = 30; rc_cfg->fps_in_flex = 0; rc_cfg->fps_out_flex = 0; rc_cfg->max_reenc_times = 1; rc_cfg->gop = enc_cmd->gop_len; block = MPP_POLL_BLOCK; ret = enc_mpi->control(enc_ctx, MPP_SET_INPUT_TIMEOUT, (MppParam)&block); if (ret) { mpp_err("enc_mpi->control MPP_SET_INPUT_TIMEOUT failed\n"); goto MPP_TEST_OUT; } block = MPP_POLL_BLOCK; ret = enc_mpi->control(enc_ctx, MPP_SET_OUTPUT_TIMEOUT, (MppParam)&block); if (ret) { mpp_err("enc_mpi->control MPP_SET_OUTPUT_TIMEOUT failed\n"); goto MPP_TEST_OUT; } ret = mpp_init(enc_ctx, MPP_CTX_ENC, enc_cmd->type); if (ret) { mpp_err("mpp_init enc failed\n"); goto MPP_TEST_OUT; } if (enc_cmd->width) mpp_enc_cfg_set_s32(cfg, "prep:width", enc_cmd->width); if (enc_cmd->height) mpp_enc_cfg_set_s32(cfg, "prep:height", enc_cmd->height); if (enc_cmd->hor_stride) mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", enc_cmd->hor_stride); if (enc_cmd->ver_stride) mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", enc_cmd->ver_stride); mpp_enc_cfg_set_s32(cfg, "prep:format", MPP_FMT_YUV420SP); mpp_enc_cfg_set_s32(cfg, "rc:mode", enc_cmd->rc_mode); switch (enc_cmd->rc_mode) { case MPP_ENC_RC_MODE_FIXQP : { /* do not set bps on fix qp mode */ } break; case MPP_ENC_RC_MODE_CBR : { /* CBR mode has narrow bound */ mpp_enc_cfg_set_s32(cfg, "rc:bps_target", enc_cmd->bps_target); mpp_enc_cfg_set_s32(cfg, "rc:bps_max", enc_cmd->bps_max ? enc_cmd->bps_max : enc_cmd->bps_target * 3 / 2); mpp_enc_cfg_set_s32(cfg, "rc:bps_min", enc_cmd->bps_min ? enc_cmd->bps_max : enc_cmd->bps_target / 2); } break; case MPP_ENC_RC_MODE_VBR : { /* CBR mode has wide bound */ mpp_enc_cfg_set_s32(cfg, "rc:bps_target", enc_cmd->bps_target); mpp_enc_cfg_set_s32(cfg, "rc:bps_max", enc_cmd->bps_max ? enc_cmd->bps_max : enc_cmd->bps_target * 17 / 16); mpp_enc_cfg_set_s32(cfg, "rc:bps_min", enc_cmd->bps_min ? enc_cmd->bps_max : enc_cmd->bps_target * 1 / 16); } break; default : { mpp_err_f("unsupport encoder rc mode %d\n", enc_cmd->rc_mode); } break; } /* fix input / output frame rate */ mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", rc_cfg->fps_in_flex); mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", rc_cfg->fps_in_num); mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denorm", rc_cfg->fps_in_denorm); mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", rc_cfg->fps_out_flex); mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num", rc_cfg->fps_out_num); mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denorm", rc_cfg->fps_out_denorm); mpp_enc_cfg_set_s32(cfg, "rc:gop", enc_cmd->gop_len ? enc_cmd->gop_len : 30 * 2); /* drop frame or not when bitrate overflow */ mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED); mpp_enc_cfg_set_u32(cfg, "rc:drop_thd", 20); /* 20% of max bps */ mpp_enc_cfg_set_u32(cfg, "rc:drop_gap", 1); /* Do not continuous drop frame */ mpp_env_get_u32("dbrh_en", &debreath_en, 0); mpp_env_get_u32("dbrh_s", &debreath_s, 16); mpp_enc_cfg_set_u32(cfg, "rc:debreath_en", debreath_en); mpp_enc_cfg_set_u32(cfg, "rc:debreath_strength", debreath_s); /* setup codec */ mpp_enc_cfg_set_s32(cfg, "codec:type", enc_cmd->type); switch (enc_cmd->type) { case MPP_VIDEO_CodingAVC : { /* * H.264 profile_idc parameter * 66 - Baseline profile * 77 - Main profile * 100 - High profile */ mpp_enc_cfg_set_s32(cfg, "h264:profile", 100); /* * H.264 level_idc parameter * 10 / 11 / 12 / 13 - qcif@15fps / cif@7.5fps / cif@15fps / cif@30fps * 20 / 21 / 22 - cif@30fps / half-D1@@25fps / D1@12.5fps * 30 / 31 / 32 - D1@25fps / 720p@30fps / 720p@60fps * 40 / 41 / 42 - 1080p@30fps / 1080p@30fps / 1080p@60fps * 50 / 51 / 52 - 4K@30fps */ mpp_enc_cfg_set_s32(cfg, "h264:level", 40); mpp_enc_cfg_set_s32(cfg, "h264:cabac_en", 1); mpp_enc_cfg_set_s32(cfg, "h264:cabac_idc", 0); mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", 1); if (enc_cmd->rc_mode == MPP_ENC_RC_MODE_FIXQP) { mpp_enc_cfg_set_s32(cfg, "h264:qp_init", 20); mpp_enc_cfg_set_s32(cfg, "h264:qp_max", 16); mpp_enc_cfg_set_s32(cfg, "h264:qp_min", 16); mpp_enc_cfg_set_s32(cfg, "h264:qp_max_i", 20); mpp_enc_cfg_set_s32(cfg, "h264:qp_min_i", 20); } else { mpp_enc_cfg_set_s32(cfg, "h264:qp_init", 26); mpp_enc_cfg_set_s32(cfg, "h264:qp_max", 51); mpp_enc_cfg_set_s32(cfg, "h264:qp_min", 10); mpp_enc_cfg_set_s32(cfg, "h264:qp_max_i", 46); mpp_enc_cfg_set_s32(cfg, "h264:qp_min_i", 18); } } break; case MPP_VIDEO_CodingMJPEG : { mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", 80); mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", 99); mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", 1); } break; case MPP_VIDEO_CodingVP8 : { mpp_enc_cfg_set_s32(cfg, "vp8:qp_init", 40); mpp_enc_cfg_set_s32(cfg, "vp8:qp_max", 127); mpp_enc_cfg_set_s32(cfg, "vp8:qp_min", 0); mpp_enc_cfg_set_s32(cfg, "vp8:qp_max_i", 127); mpp_enc_cfg_set_s32(cfg, "vp8:qp_min_i", 0); } break; case MPP_VIDEO_CodingHEVC : { mpp_enc_cfg_set_s32(cfg, "h265:qp_init", enc_cmd->rc_mode == MPP_ENC_RC_MODE_FIXQP ? -1 : 26); mpp_enc_cfg_set_s32(cfg, "h265:qp_max", 51); mpp_enc_cfg_set_s32(cfg, "h265:qp_min", 10); mpp_enc_cfg_set_s32(cfg, "h265:qp_max_i", 46); mpp_enc_cfg_set_s32(cfg, "h265:qp_min_i", 18); } break; default : { mpp_err_f("unsupport encoder coding type %d\n", enc_cmd->type); } break; } ret = enc_mpi->control(enc_ctx, MPP_ENC_SET_CFG, cfg); if (ret) { mpp_err("mpi control enc set cfg failed ret %d\n", ret); goto MPP_TEST_OUT; } /* optional */ ret = enc_mpi->control(enc_ctx, MPP_ENC_SET_SEI_CFG, &sei_mode); if (ret) { mpp_err("mpi control enc set sei cfg failed ret %d\n", ret); goto MPP_TEST_OUT; } MPP_TEST_OUT: return ret; } static MPP_RET mpi_rc_post_dec_init(MpiRc2TestCtx *ctx) { MpiEncTestArgs *enc_cmd = ctx->enc_cmd; MppApi *dec_mpi = NULL; MppCtx dec_ctx = NULL; MppPollType block = MPP_POLL_NON_BLOCK; RK_U32 need_split = 0; MPP_RET ret = MPP_OK; // decoder init ret = mpp_create(&ctx->dec_ctx_post, &ctx->dec_mpi_post); if (ret) { mpp_err("mpp_create decoder failed\n"); goto MPP_TEST_OUT; } dec_mpi = ctx->dec_mpi_post; dec_ctx = ctx->dec_ctx_post; ret = mpp_packet_init(&ctx->dec_pkt_post, ctx->dec_in_buf_post, ctx->dec_in_buf_post_size); if (ret) { mpp_err("mpp_packet_init failed\n"); goto MPP_TEST_OUT; } ret = dec_mpi->control(dec_ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, &need_split); if (ret) { mpp_err("dec_mpi->control failed\n"); goto MPP_TEST_OUT; } ret = dec_mpi->control(dec_ctx, MPP_SET_INPUT_TIMEOUT, (MppParam)&block); if (ret) { mpp_err("dec_mpi->control dec MPP_SET_INPUT_TIMEOUT failed\n"); goto MPP_TEST_OUT; } block = MPP_POLL_NON_BLOCK; ret = dec_mpi->control(dec_ctx, MPP_SET_OUTPUT_TIMEOUT, (MppParam)&block); if (ret) { mpp_err("dec_mpi->control MPP_SET_OUTPUT_TIMEOUT failed\n"); goto MPP_TEST_OUT; } ret = mpp_init(dec_ctx, MPP_CTX_DEC, enc_cmd->type); if (ret) { mpp_err("mpp_init dec failed\n"); goto MPP_TEST_OUT; } MPP_TEST_OUT: return ret; } static MPP_RET mpi_rc_dec_post_decode(MpiRc2TestCtx *ctx, MppFrame orig_frm) { MPP_RET ret = MPP_OK; RK_S32 dec_pkt_done = 0; MppFrame out_frm = NULL; do { if (ctx->pkt_eos) mpp_packet_set_eos(ctx->dec_pkt_post); // send the packet first if packet is not done if (!dec_pkt_done) { ret = ctx->dec_mpi_post->decode_put_packet(ctx->dec_ctx_post, ctx->dec_pkt_post); if (MPP_OK == ret) dec_pkt_done = 1; } // then get all available frame and release do { RK_S32 dec_get_frm = 0; RK_U32 dec_frm_eos = 0; ret = ctx->dec_mpi_post->decode_get_frame(ctx->dec_ctx_post, &out_frm); if (ret) { mpp_err("decode_get_frame failed ret %d\n", ret); break; } if (out_frm) { if (mpp_frame_get_info_change(out_frm)) { mpp_log("decode_get_frame get info changed found\n"); ctx->dec_mpi_post->control(ctx->dec_ctx_post, MPP_DEC_SET_INFO_CHANGE_READY, NULL); } else { mpi_rc_calc_stat(ctx, orig_frm, out_frm); mpi_rc_log_stat(ctx, ctx->frm_idx, !((ctx->frm_idx - ctx->calc_base_idx + 1) % ctx->rc_cfg.fps_in_num), 0); dec_get_frm = 1; } dec_frm_eos = mpp_frame_get_eos(out_frm); mpp_frame_deinit(&out_frm); out_frm = NULL; } // if last packet is send but last frame is not found continue if (ctx->pkt_eos && dec_pkt_done && !dec_frm_eos) continue; if (dec_get_frm) break; } while (1); if (dec_pkt_done) break; msleep(5); } while (1); return ret; } static MPP_RET mpi_rc_pre_dec_init(MpiRc2TestCtx *ctx) { RK_U32 need_split = 1; MppPollType block = MPP_POLL_NON_BLOCK; RK_U32 fast_en = 0; MppApi *dec_mpi = NULL; MppCtx dec_ctx = NULL; MppFrameFormat format = MPP_FMT_YUV420SP; RK_U32 fbc_en = 0; MPP_RET ret = MPP_OK; mpp_env_get_u32("fbc_dec_en", &fbc_en, 0); mpp_env_get_u32("fast_en", &fast_en, 0); if (fbc_en) format = format | MPP_FRAME_FBC_AFBC_V2; // decoder init ret = mpp_create(&ctx->dec_ctx_pre, &ctx->dec_mpi_pre); if (ret) { mpp_err("mpp_create decoder failed\n"); goto MPP_TEST_OUT; } dec_mpi = ctx->dec_mpi_pre; dec_ctx = ctx->dec_ctx_pre; ret = mpp_packet_init(&ctx->dec_pkt_pre, ctx->dec_in_buf_pre, ctx->dec_in_buf_pre_size); if (ret) { mpp_err("mpp_packet_init failed\n"); goto MPP_TEST_OUT; } ret = dec_mpi->control(dec_ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, &need_split); if (ret) { mpp_err("dec_mpi->control failed\n"); goto MPP_TEST_OUT; } ret = dec_mpi->control(dec_ctx, MPP_DEC_SET_PARSER_FAST_MODE, &fast_en); if (ret) { mpp_err("dec_mpi->control failed\n"); goto MPP_TEST_OUT; } ret = dec_mpi->control(dec_ctx, MPP_SET_INPUT_TIMEOUT, (MppParam)&block); if (ret) { mpp_err("dec_mpi->control dec MPP_SET_INPUT_TIMEOUT failed\n"); goto MPP_TEST_OUT; } block = MPP_POLL_NON_BLOCK; ret = dec_mpi->control(dec_ctx, MPP_SET_OUTPUT_TIMEOUT, (MppParam)&block); if (ret) { mpp_err("dec_mpi->control MPP_SET_OUTPUT_TIMEOUT failed\n"); goto MPP_TEST_OUT; } ret = mpp_init(dec_ctx, MPP_CTX_DEC, ctx->dec_type); if (ret) { mpp_err("mpp_init dec failed\n"); goto MPP_TEST_OUT; } ret = dec_mpi->control(dec_ctx, MPP_DEC_SET_OUTPUT_FORMAT, &format); if (ret) { mpp_err("dec_mpi->control failed\n"); goto MPP_TEST_OUT; } MPP_TEST_OUT: return ret; } static MPP_RET mpi_rc_info_change(MpiRc2TestCtx *ctx, MppFrame frm) { MPP_RET ret = MPP_OK; mpp_enc_cfg_set_s32(ctx->cfg, "prep:width", mpp_frame_get_width(frm)); mpp_enc_cfg_set_s32(ctx->cfg, "prep:height", mpp_frame_get_height(frm)); mpp_enc_cfg_set_s32(ctx->cfg, "prep:hor_stride", mpp_frame_get_hor_stride(frm)); mpp_enc_cfg_set_s32(ctx->cfg, "prep:ver_stride", mpp_frame_get_ver_stride(frm)); mpp_enc_cfg_set_s32(ctx->cfg, "prep:format", mpp_frame_get_fmt(frm)); ret = ctx->enc_mpi->control(ctx->enc_ctx, MPP_ENC_SET_CFG, ctx->cfg); ctx->dec_mpi_post->control(ctx->dec_ctx_post, MPP_DEC_SET_FRAME_INFO, (MppParam)frm); return ret; } static MPP_RET mpi_rc_enc(MpiRc2TestCtx *ctx) { MPP_RET ret = MPP_OK; MppApi *mpi = ctx->dec_mpi_pre; MppCtx dec_ctx = ctx->dec_ctx_pre; MppFrame frm = NULL; do { ret = mpi->decode_get_frame(dec_ctx, &frm); if (ret) { mpp_err("decode_get_frame failed ret %d\n", ret); break; } if (frm) { ctx->frm_eos = mpp_frame_get_eos(frm); if (mpp_frame_get_info_change(frm)) { mpp_log("decode_get_frame get info changed found\n"); mpi->control(dec_ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); mpi_rc_info_change(ctx, frm); ctx->start_enc = mpp_time(); } else { void *ptr; size_t len; /*force eos*/ if ((ctx->enc_cmd->frame_num > 0) && (ctx->frm_idx > ctx->enc_cmd->frame_num)) { ctx->loop_end = 1; mpp_frame_set_eos(frm, 1); ctx->frm_eos = mpp_frame_get_eos(frm); } #ifndef ASYN_ENC ctx->enc_mpi->encode_put_frame(ctx->enc_ctx, frm); ctx->enc_mpi->encode_get_packet(ctx->enc_ctx, &ctx->enc_pkt); #else LAST_PACKET: ctx->enc_mpi->encode(ctx->enc_ctx, frm, &ctx->enc_pkt); frm = NULL; //ASYN_ENC will free after get packet #endif if (ctx->enc_pkt) { len = mpp_packet_get_length(ctx->enc_pkt); ctx->stat.frame_size = len; ctx->stream_size_1s += len; ctx->total_bits += len * 8; if ((ctx->frm_idx - ctx->calc_base_idx + 1) % ctx->rc_cfg.fps_in_num == 0) { ctx->stat.ins_bitrate = ctx->stream_size_1s; ctx->stream_size_1s = 0; } ptr = mpp_packet_get_pos(ctx->enc_pkt); if (ctx->file.fp_enc_out) fwrite(ptr, 1, len, ctx->file.fp_enc_out); /* decode one frame */ // write packet to dec input mpp_packet_write(ctx->dec_pkt_post, 0, ptr, len); // reset pos mpp_packet_set_pos(ctx->dec_pkt_post, ctx->dec_in_buf_post); mpp_packet_set_length(ctx->dec_pkt_post, len); mpp_packet_set_size(ctx->dec_pkt_post, len); if (mpp_packet_has_meta(ctx->enc_pkt)) { MppFrame frame = NULL; MppMeta meta = mpp_packet_get_meta(ctx->enc_pkt); mpp_meta_get_frame(meta, KEY_INPUT_FRAME, &frame); if (ctx->enc_cmd->ssim_en || ctx->enc_cmd->psnr_en) { mpp_packet_write(ctx->dec_pkt_post, 0, ptr, len); mpi_rc_dec_post_decode(ctx, frame); } if (frame) { frm = frame; //ASYN_ENC delay free } } else { if (ctx->enc_cmd->ssim_en || ctx->enc_cmd->psnr_en) { mpp_packet_write(ctx->dec_pkt_post, 0, ptr, len); mpi_rc_dec_post_decode(ctx, frm); } } ctx->enc_pkt_eos = mpp_packet_get_eos(ctx->enc_pkt); ctx->frm_idx++; mpp_packet_deinit(&ctx->enc_pkt); } } mpp_frame_deinit(&frm); frm = NULL; } else { msleep(3); continue; } #ifdef ANSY_ENC if (ctx->frm_eos && !ctx->enc_pkt_eos) { goto LAST_PACKET; } #endif if (ctx->enc_pkt_eos) { break; } } while (1); return ret; } static MPP_RET mpi_rc_buffer_init(MpiRc2TestCtx *ctx) { /* NOTE: packet buffer may overflow */ size_t packet_size = SZ_256K; MPP_RET ret = MPP_OK; ret = mpp_buffer_group_get_internal(&ctx->pkt_grp, MPP_BUFFER_TYPE_ION); if (ret) { mpp_err("failed to get buffer group for output packet ret %d\n", ret); goto RET; } ret = mpp_buffer_get(ctx->pkt_grp, &ctx->enc_pkt_buf, packet_size); if (ret) { mpp_err("failed to get buffer for input frame ret %d\n", ret); goto RET; } ctx->dec_in_buf_post = mpp_calloc(RK_U8, packet_size); if (NULL == ctx->dec_in_buf_post) { mpp_err("mpi_dec_test malloc input stream buffer failed\n"); goto RET; } ctx->dec_in_buf_post_size = packet_size; ctx->frm_idx = 0; ctx->calc_base_idx = 0; ctx->stream_size_1s = 0; return ret; RET: ctx->dec_ctx_pre = NULL; ctx->dec_ctx_post = NULL; MPP_FREE(ctx->dec_in_buf_post); if (ctx->enc_pkt_buf) { mpp_buffer_put(ctx->enc_pkt_buf); ctx->enc_pkt_buf = NULL; } if (ctx->pkt_grp) { mpp_buffer_group_put(ctx->pkt_grp); ctx->pkt_grp = NULL; } return ret; } #define CHECK_RET(x) do { \ if (x < 0) { \ mpp_err_f("%d failed\n"); \ goto MPP_TEST_OUT; \ } \ } while (0) static void *rc2_pre_dec_thread(void *param) { MpiRc2TestCtx *ctx = (MpiRc2TestCtx *)param; FileReader reader = ctx->reader; FileBufSlot *slot = NULL; MppPacket packet = ctx->dec_pkt_pre; MppApi *mpi = ctx->dec_mpi_pre; MppCtx dec_ctx = ctx->dec_ctx_pre; MPP_RET ret = MPP_OK; RK_S32 dec_pkt_done = 0; while (!ctx->loop_end) { RK_U32 pkt_eos = 0; dec_pkt_done = 0; ret = reader_index_read(reader, ctx->pre_pkt_idx++, &slot); pkt_eos = slot->eos; if (pkt_eos) { if (ctx->enc_cmd->frame_num < 0) { ctx->pre_pkt_idx = 0; pkt_eos = 0; } else if (!ctx->enc_cmd->frame_num) { ctx->loop_end = 1; } else { ctx->pre_pkt_idx = 0; pkt_eos = 0; } } if ((ctx->enc_cmd->frame_num > 0) && (ctx->frm_idx > ctx->enc_cmd->frame_num)) { mpp_log("frm_idx %d, frame_num %d", ctx->frm_idx, ctx->enc_cmd->frame_num); ctx->loop_end = 1; } mpp_packet_set_data(packet, slot->data); mpp_packet_set_size(packet, slot->size); mpp_packet_set_pos(packet, slot->data); mpp_packet_set_length(packet, slot->size); if (ctx->loop_end) { mpp_packet_set_eos(packet); ctx->pkt_eos = 1; } do { ret = mpi->decode_put_packet(dec_ctx, packet); if (MPP_OK == ret) dec_pkt_done = 1; else msleep(5); if (ctx->loop_end) { break; } } while (!dec_pkt_done); if (ctx->pkt_eos) { mpp_log("dec stream finish\n"); break; } } mpp_log("rc2_pre_dec_thread exit"); return NULL; } static MPP_RET mpi_rc_codec(MpiRc2TestCtx *ctx) { MPP_RET ret = MPP_OK; RK_S64 t_e; CHECK_RET(mpi_rc_buffer_init(ctx)); CHECK_RET(mpi_rc_post_dec_init(ctx)); CHECK_RET(mpi_rc_pre_dec_init(ctx)); CHECK_RET(mpp_enc_cfg_init(&ctx->cfg)); CHECK_RET(mpi_rc_enc_init(ctx)); pthread_create(&ctx->dec_thr, NULL, rc2_pre_dec_thread, ctx); while (1) { mpi_rc_enc(ctx); if (ctx->enc_pkt_eos) { mpp_log("stream finish\n"); break; } } t_e = mpp_time(); RK_U64 elapsed_time = t_e - ctx->start_enc; float frame_rate = (float)ctx->frm_idx * 1000000 / elapsed_time; mpp_log("enc_dec %d frame use time %lld ms frm rate %.2f\n", ctx->frm_idx, elapsed_time / 1000, frame_rate); if (ctx->frm_idx) { MpiEncTestArgs* enc_cmd = ctx->enc_cmd; mpp_log("%s: %s: average: bps %d | psnr %5.2f | ssim %5.5f", enc_cmd->file_input, enc_cmd->gop_mode ? "smart_p" : "normal_p", 30 * (RK_U32)(ctx->total_bits / ctx->frm_idx), ctx->total_psnrs / ctx->frm_idx, ctx->total_ssims / ctx->frm_idx); if (ctx->file.fp_stat) fprintf(ctx->file.fp_stat, "%s: %s: average: bps %dk | psnr %5.2f | ssim %5.5f \n", enc_cmd->file_input, enc_cmd->gop_mode ? "smart_p" : "normal_p", 30 * (RK_U32)(ctx->total_bits / ctx->frm_idx) / 1000, ctx->total_psnrs / ctx->frm_idx, ctx->total_ssims / ctx->frm_idx); } CHECK_RET(ctx->enc_mpi->reset(ctx->enc_ctx)); CHECK_RET(ctx->dec_mpi_pre->reset(ctx->dec_ctx_pre)); CHECK_RET(ctx->dec_mpi_post->reset(ctx->dec_ctx_post)); MPP_TEST_OUT: // encoder deinit pthread_join(ctx->dec_thr, NULL); if (ctx->enc_ctx) { mpp_destroy(ctx->enc_ctx); ctx->enc_ctx = NULL; } if (ctx->enc_pkt_buf) { mpp_buffer_put(ctx->enc_pkt_buf); ctx->enc_pkt_buf = NULL; } if (ctx->pkt_grp) { mpp_buffer_group_put(ctx->pkt_grp); ctx->pkt_grp = NULL; } // decoder deinit if (ctx->dec_pkt_post) { mpp_packet_deinit(&ctx->dec_pkt_post); ctx->dec_pkt_post = NULL; } if (ctx->dec_pkt_pre) { mpp_packet_deinit(&ctx->dec_pkt_pre); ctx->dec_pkt_pre = NULL; } if (ctx->cfg) { mpp_enc_cfg_deinit(ctx->cfg); ctx->cfg = NULL; } if (ctx->dec_ctx_post) { mpp_destroy(ctx->dec_ctx_post); ctx->dec_ctx_post = NULL; } if (ctx->dec_ctx_pre) { mpp_destroy(ctx->dec_ctx_pre); ctx->dec_ctx_pre = NULL; } MPP_FREE(ctx->dec_in_buf_post); MPP_FREE(ctx->dec_in_buf_pre); return ret; } int main(int argc, char **argv) { MpiEncTestArgs* enc_cmd = mpi_enc_test_cmd_get(); MpiRc2TestCtx *ctx = NULL; MPP_RET ret = MPP_OK; ret = mpi_enc_test_cmd_update_by_args(enc_cmd, argc, argv); if (ret) goto DONE; mpi_enc_test_cmd_show_opt(enc_cmd); ctx = mpp_calloc(MpiRc2TestCtx, 1); if (NULL == ctx) { ret = MPP_ERR_MALLOC; goto DONE; } ctx->enc_cmd = enc_cmd; ret = mpi_rc_init(ctx); if (ret) { mpp_err("mpi_rc_init failded ret %d", ret); goto DONE; } ret = mpi_rc_codec(ctx); if (ret) mpp_err("mpi_rc_codec failded ret %d", ret); DONE: if (ctx) { mpi_rc_deinit(ctx); ctx = NULL; } mpi_enc_test_cmd_put(enc_cmd); return (int)ret; }