You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
762 lines
25 KiB
762 lines
25 KiB
#include <stdio.h> |
|
#include <string.h> |
|
|
|
#include "mpp_encoder.h" |
|
#include "rockchip/mpp_buffer.h" |
|
|
|
#define MPP_ALIGN(x, a) (((x)+(a)-1)&~((a)-1)) |
|
#define SZ_4K 4096 |
|
#define LOGD printf |
|
// #define LOGD |
|
#define LOGE printf |
|
|
|
int MppEncoder::InitParams(MppEncoderParams& params) |
|
{ |
|
memcpy(&enc_params, ¶ms, sizeof(MppEncoderParams)); |
|
|
|
// get paramter from cmd |
|
if (enc_params.hor_stride == 0) { |
|
enc_params.hor_stride = MPP_ALIGN(enc_params.width, 16); |
|
} |
|
if (enc_params.ver_stride == 0) { |
|
enc_params.ver_stride = (MPP_ALIGN(enc_params.height, 16)); |
|
} |
|
|
|
if (enc_params.fps_in_den == 0) |
|
enc_params.fps_in_den = 1; |
|
if (enc_params.fps_in_num == 0) |
|
enc_params.fps_in_num = 30; |
|
if (enc_params.fps_out_den == 0) |
|
enc_params.fps_out_den = 1; |
|
if (enc_params.fps_out_num == 0) |
|
enc_params.fps_out_num = 30; |
|
|
|
if (!enc_params.bps) |
|
enc_params.bps = enc_params.width * enc_params.height / 8 * (enc_params.fps_out_num / enc_params.fps_out_den); |
|
|
|
this->mdinfo_size = (MPP_VIDEO_CodingHEVC == enc_params.type) ? |
|
(MPP_ALIGN(enc_params.hor_stride, 32) >> 5) * |
|
(MPP_ALIGN(enc_params.ver_stride, 32) >> 5) * 16 : |
|
(MPP_ALIGN(enc_params.hor_stride, 64) >> 6) * |
|
(MPP_ALIGN(enc_params.ver_stride, 16) >> 4) * 16; |
|
|
|
// update resource parameter |
|
switch (enc_params.fmt & MPP_FRAME_FMT_MASK) { |
|
case MPP_FMT_YUV420SP: |
|
case MPP_FMT_YUV420P: { |
|
this->frame_size = MPP_ALIGN(enc_params.hor_stride, 64) * MPP_ALIGN(enc_params.ver_stride, 64) * 3 / 2; |
|
} break; |
|
|
|
case MPP_FMT_YUV422_YUYV : |
|
case MPP_FMT_YUV422_YVYU : |
|
case MPP_FMT_YUV422_UYVY : |
|
case MPP_FMT_YUV422_VYUY : |
|
case MPP_FMT_YUV422P : |
|
case MPP_FMT_YUV422SP : { |
|
this->frame_size = MPP_ALIGN(enc_params.hor_stride, 64) * MPP_ALIGN(enc_params.ver_stride, 64) * 2; |
|
} break; |
|
case MPP_FMT_RGB444 : |
|
case MPP_FMT_BGR444 : |
|
case MPP_FMT_RGB555 : |
|
case MPP_FMT_BGR555 : |
|
case MPP_FMT_RGB565 : |
|
case MPP_FMT_BGR565 : |
|
case MPP_FMT_RGB888 : |
|
case MPP_FMT_BGR888 : |
|
case MPP_FMT_RGB101010 : |
|
case MPP_FMT_BGR101010 : |
|
case MPP_FMT_ARGB8888 : |
|
case MPP_FMT_ABGR8888 : |
|
case MPP_FMT_BGRA8888 : |
|
case MPP_FMT_RGBA8888 : { |
|
this->frame_size = MPP_ALIGN(enc_params.hor_stride, 64) * MPP_ALIGN(enc_params.ver_stride, 64); |
|
} break; |
|
|
|
default: { |
|
this->frame_size = MPP_ALIGN(enc_params.hor_stride, 64) * MPP_ALIGN(enc_params.ver_stride, 64) * 4; |
|
} break; |
|
} |
|
|
|
if (MPP_FRAME_FMT_IS_FBC(enc_params.fmt)) { |
|
if ((enc_params.fmt & MPP_FRAME_FBC_MASK) == MPP_FRAME_FBC_AFBC_V1) |
|
this->header_size = MPP_ALIGN(MPP_ALIGN(enc_params.width, 16) * MPP_ALIGN(enc_params.height, 16) / 16, SZ_4K); |
|
else |
|
this->header_size = MPP_ALIGN(enc_params.width, 16) * MPP_ALIGN(enc_params.height, 16) / 16; |
|
} else { |
|
this->header_size = 0; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
int MppEncoder::SetupEncCfg() |
|
{ |
|
MPP_RET ret; |
|
|
|
ret = mpp_enc_cfg_init(&cfg); |
|
if (ret) { |
|
LOGE("mpp_enc_cfg_init failed ret %d\n", ret); |
|
return -1; |
|
} |
|
|
|
/* setup default parameter */ |
|
if (enc_params.fps_in_den == 0) |
|
enc_params.fps_in_den = 1; |
|
if (enc_params.fps_in_num == 0) |
|
enc_params.fps_in_num = 30; |
|
if (enc_params.fps_out_den == 0) |
|
enc_params.fps_out_den = 1; |
|
if (enc_params.fps_out_num == 0) |
|
enc_params.fps_out_num = 30; |
|
|
|
if (!enc_params.bps) |
|
enc_params.bps = enc_params.width * enc_params.height / 8 * (enc_params.fps_out_num / enc_params.fps_out_den); |
|
|
|
mpp_enc_cfg_set_s32(cfg, "prep:width", enc_params.width); |
|
mpp_enc_cfg_set_s32(cfg, "prep:height", enc_params.height); |
|
mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", enc_params.hor_stride); |
|
mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", enc_params.ver_stride); |
|
mpp_enc_cfg_set_s32(cfg, "prep:format", enc_params.fmt); |
|
|
|
mpp_enc_cfg_set_s32(cfg, "rc:mode", enc_params.rc_mode); |
|
|
|
/* fix input / output frame rate */ |
|
mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", enc_params.fps_in_flex); |
|
mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", enc_params.fps_in_num); |
|
mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denorm", enc_params.fps_in_den); |
|
mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", enc_params.fps_out_flex); |
|
mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num", enc_params.fps_out_num); |
|
mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denorm", enc_params.fps_out_den); |
|
mpp_enc_cfg_set_s32(cfg, "rc:gop", enc_params.gop_len ? enc_params.gop_len : enc_params.fps_out_num * 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 */ |
|
|
|
/* setup bitrate for different rc_mode */ |
|
mpp_enc_cfg_set_s32(cfg, "rc:bps_target", enc_params.bps); |
|
switch (enc_params.rc_mode) { |
|
case MPP_ENC_RC_MODE_FIXQP : { |
|
/* do not setup bitrate on FIXQP mode */ |
|
} break; |
|
case MPP_ENC_RC_MODE_CBR : { |
|
/* CBR mode has narrow bound */ |
|
mpp_enc_cfg_set_s32(cfg, "rc:bps_max", enc_params.bps_max ? enc_params.bps_max : enc_params.bps * 17 / 16); |
|
mpp_enc_cfg_set_s32(cfg, "rc:bps_min", enc_params.bps_min ? enc_params.bps_min : enc_params.bps * 15 / 16); |
|
} break; |
|
case MPP_ENC_RC_MODE_VBR : |
|
case MPP_ENC_RC_MODE_AVBR : { |
|
/* VBR mode has wide bound */ |
|
mpp_enc_cfg_set_s32(cfg, "rc:bps_max", enc_params.bps_max ? enc_params.bps_max : enc_params.bps * 17 / 16); |
|
mpp_enc_cfg_set_s32(cfg, "rc:bps_min", enc_params.bps_min ? enc_params.bps_min : enc_params.bps * 1 / 16); |
|
} break; |
|
default : { |
|
/* default use CBR mode */ |
|
mpp_enc_cfg_set_s32(cfg, "rc:bps_max", enc_params.bps_max ? enc_params.bps_max : enc_params.bps * 17 / 16); |
|
mpp_enc_cfg_set_s32(cfg, "rc:bps_min", enc_params.bps_min ? enc_params.bps_min : enc_params.bps * 15 / 16); |
|
} break; |
|
} |
|
|
|
/* setup qp for different codec and rc_mode */ |
|
switch (enc_params.type) { |
|
case MPP_VIDEO_CodingAVC : |
|
case MPP_VIDEO_CodingHEVC : { |
|
switch (enc_params.rc_mode) { |
|
case MPP_ENC_RC_MODE_FIXQP : { |
|
RK_S32 fix_qp = enc_params.qp_init; |
|
|
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_init", fix_qp); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_max", fix_qp); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_min", fix_qp); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", fix_qp); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", fix_qp); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 0); |
|
} break; |
|
case MPP_ENC_RC_MODE_CBR : |
|
case MPP_ENC_RC_MODE_VBR : |
|
case MPP_ENC_RC_MODE_AVBR : { |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_init", -1); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_max", 51); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_min", 10); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", 51); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 10); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2); |
|
} break; |
|
default : { |
|
LOGE("unsupport encoder rc mode %d\n", enc_params.rc_mode); |
|
} break; |
|
} |
|
} break; |
|
case MPP_VIDEO_CodingVP8 : { |
|
/* vp8 only setup base qp range */ |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_init", 40); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_max", 127); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_min", 0); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", 127); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 0); |
|
mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 6); |
|
} break; |
|
case MPP_VIDEO_CodingMJPEG : { |
|
/* jpeg use special codec config to control qtable */ |
|
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; |
|
default : { |
|
} break; |
|
} |
|
|
|
/* setup codec */ |
|
mpp_enc_cfg_set_s32(cfg, "codec:type", enc_params.type); |
|
switch (enc_params.type) { |
|
case MPP_VIDEO_CodingAVC : { |
|
RK_U32 constraint_set = enc_params.constraint_set; |
|
|
|
/* |
|
* 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 (constraint_set & 0x3f0000) |
|
mpp_enc_cfg_set_s32(cfg, "h264:constraint_set", constraint_set); |
|
} break; |
|
case MPP_VIDEO_CodingHEVC : |
|
case MPP_VIDEO_CodingMJPEG : |
|
case MPP_VIDEO_CodingVP8 : { |
|
} break; |
|
default : { |
|
LOGE("unsupport encoder coding type %d\n", enc_params.type); |
|
} break; |
|
} |
|
|
|
if (enc_params.split_mode) { |
|
LOGD("%p split mode %d arg %d out %d\n", mpp_ctx, |
|
enc_params.split_mode, enc_params.split_arg, enc_params.split_out); |
|
mpp_enc_cfg_set_s32(cfg, "split:mode", enc_params.split_mode); |
|
mpp_enc_cfg_set_s32(cfg, "split:arg", enc_params.split_arg); |
|
mpp_enc_cfg_set_s32(cfg, "split:out", enc_params.split_out); |
|
} |
|
|
|
mpp_enc_cfg_set_s32(cfg, "prep:mirroring", enc_params.mirroring); |
|
mpp_enc_cfg_set_s32(cfg, "prep:rotation", enc_params.rotation); |
|
mpp_enc_cfg_set_s32(cfg, "prep:flip", enc_params.flip); |
|
|
|
ret = mpp_mpi->control(mpp_ctx, MPP_ENC_SET_CFG, cfg); |
|
if (ret) { |
|
LOGE("mpi control enc set cfg failed ret %d\n", ret); |
|
goto RET; |
|
} |
|
|
|
#if 0 |
|
/* optional */ |
|
{ |
|
ret = mpp_mpi->control(mpp_ctx, MPP_ENC_SET_SEI_CFG, &enc_params.sei_mode); |
|
if (ret) { |
|
LOGE("mpi control enc set sei cfg failed ret %d\n", ret); |
|
goto RET; |
|
} |
|
} |
|
#endif |
|
|
|
if (enc_params.type == MPP_VIDEO_CodingAVC || enc_params.type == MPP_VIDEO_CodingHEVC) { |
|
enc_params.header_mode = MPP_ENC_HEADER_MODE_EACH_IDR; |
|
ret = mpp_mpi->control(mpp_ctx, MPP_ENC_SET_HEADER_MODE, &enc_params.header_mode); |
|
if (ret) { |
|
LOGE("mpi control enc set header mode failed ret %d\n", ret); |
|
goto RET; |
|
} |
|
} |
|
|
|
#if 0 |
|
RK_U32 gop_mode = enc_params.gop_mode; |
|
if (gop_mode) { |
|
MppEncRefCfg ref; |
|
|
|
mpp_enc_ref_cfg_init(&ref); |
|
|
|
if (enc_params.gop_mode < 4) |
|
mpi_enc_gen_ref_cfg(ref, gop_mode); |
|
else |
|
mpi_enc_gen_smart_gop_ref_cfg(ref, enc_params.gop_len, enc_params.vi_len); |
|
|
|
ret = mpp_mpi->control(mpp_ctx, MPP_ENC_SET_REF_CFG, ref); |
|
if (ret) { |
|
LOGE("mpi control enc set ref cfg failed ret %d\n", ret); |
|
goto RET; |
|
} |
|
mpp_enc_ref_cfg_deinit(&ref); |
|
} |
|
|
|
if (enc_params.roi_enable) { |
|
mpp_enc_roi_init(&enc_params.roi_mpp_ctx, enc_params.width, enc_params.height, enc_params.type, 4); |
|
mpp_assert(enc_params.roi_mpp_ctx); |
|
} |
|
#endif |
|
|
|
RET: |
|
return ret; |
|
} |
|
|
|
MppEncoder::MppEncoder() { |
|
memset(&enc_params, 0, sizeof(MppEncoderParams)); |
|
this->mpp_ctx = NULL; |
|
this->mpp_mpi = NULL; |
|
memset(&osd_data, 0, sizeof(MppEncOSDData)); |
|
} |
|
|
|
MppEncoder::~MppEncoder() { |
|
if (this->mpp_ctx) { |
|
mpp_destroy(this->mpp_ctx); |
|
this->mpp_ctx = NULL; |
|
} |
|
|
|
if (this->cfg) { |
|
mpp_enc_cfg_deinit(this->cfg); |
|
this->cfg = NULL; |
|
} |
|
|
|
if (this->frm_buf) { |
|
mpp_buffer_put(this->frm_buf); |
|
this->frm_buf = NULL; |
|
} |
|
|
|
if (this->pkt_buf) { |
|
mpp_buffer_put(this->pkt_buf); |
|
this->pkt_buf = NULL; |
|
} |
|
|
|
if (this->md_info) { |
|
mpp_buffer_put(this->md_info); |
|
this->md_info = NULL; |
|
} |
|
|
|
if (this->osd_data.buf) { |
|
mpp_buffer_put(this->osd_data.buf); |
|
this->osd_data.buf = NULL; |
|
} |
|
|
|
if (this->buf_grp) { |
|
mpp_buffer_group_put(this->buf_grp); |
|
this->buf_grp = NULL; |
|
} |
|
} |
|
|
|
int MppEncoder::Init(MppEncoderParams& params, void* userdata) { |
|
int ret; |
|
MppPollType timeout = MPP_POLL_BLOCK; |
|
|
|
this->userdata = userdata; |
|
|
|
this->InitParams(params); |
|
|
|
ret = mpp_buffer_group_get_internal(&this->buf_grp, MPP_BUFFER_TYPE_DRM); |
|
if (ret) { |
|
LOGD("failed to get mpp buffer group ret %d\n", ret); |
|
goto MPP_TEST_OUT; |
|
} |
|
|
|
ret = mpp_buffer_get(this->buf_grp, &this->pkt_buf, this->frame_size); |
|
if (ret) { |
|
LOGD("failed to get buffer for output packet ret %d\n", ret); |
|
goto MPP_TEST_OUT; |
|
} |
|
|
|
ret = mpp_buffer_get(this->buf_grp, &this->md_info, this->mdinfo_size); |
|
if (ret) { |
|
LOGD("failed to get buffer for motion info output packet ret %d\n", ret); |
|
goto MPP_TEST_OUT; |
|
} |
|
|
|
// encoder demo |
|
ret = mpp_create(&this->mpp_ctx, &this->mpp_mpi); |
|
if (ret) { |
|
LOGE("mpp_create failed ret %d\n", ret); |
|
goto MPP_TEST_OUT; |
|
} |
|
|
|
LOGD("%p encoder test start w %d h %d type %d\n", |
|
this->mpp_ctx, enc_params.width, enc_params.height, enc_params.type); |
|
|
|
ret = mpp_mpi->control(mpp_ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout); |
|
if (MPP_OK != ret) { |
|
LOGE("mpi control set output timeout %d ret %d\n", timeout, ret); |
|
goto MPP_TEST_OUT; |
|
} |
|
|
|
ret = mpp_init(mpp_ctx, MPP_CTX_ENC, enc_params.type); |
|
if (ret) { |
|
LOGE("mpp_init failed ret %d\n", ret); |
|
goto MPP_TEST_OUT; |
|
} |
|
|
|
this->SetupEncCfg(); |
|
|
|
MPP_TEST_OUT: |
|
if (ret) { |
|
if (this->mpp_ctx) { |
|
mpp_destroy(this->mpp_ctx); |
|
this->mpp_ctx = NULL; |
|
} |
|
|
|
if (this->cfg) { |
|
mpp_enc_cfg_deinit(this->cfg); |
|
this->cfg = NULL; |
|
} |
|
|
|
if (this->frm_buf) { |
|
mpp_buffer_put(this->frm_buf); |
|
this->frm_buf = NULL; |
|
} |
|
|
|
if (this->pkt_buf) { |
|
mpp_buffer_put(this->pkt_buf); |
|
this->pkt_buf = NULL; |
|
} |
|
|
|
if (this->md_info) { |
|
mpp_buffer_put(this->md_info); |
|
this->md_info = NULL; |
|
} |
|
|
|
if (this->osd_data.buf) { |
|
mpp_buffer_put(this->osd_data.buf); |
|
this->osd_data.buf = NULL; |
|
} |
|
|
|
if (this->buf_grp) { |
|
mpp_buffer_group_put(this->buf_grp); |
|
this->buf_grp = NULL; |
|
} |
|
|
|
// if (this->roi_ctx) { |
|
// mpp_enc_roi_deinit(this->roi_ctx); |
|
// this->roi_ctx = NULL; |
|
// } |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
int MppEncoder::SetCallback(MppEncoderFrameCallback callback) { |
|
this->callback = callback; |
|
return 0; |
|
} |
|
|
|
int MppEncoder::GetHeader(char* enc_buf, int max_size) { |
|
int ret; |
|
void* out_ptr = enc_buf; |
|
size_t out_len = 0; |
|
|
|
if (enc_params.type == MPP_VIDEO_CodingAVC || enc_params.type == MPP_VIDEO_CodingHEVC) { |
|
MppPacket packet = NULL; |
|
|
|
/* |
|
* Can use packet with normal malloc buffer as input not pkt_buf. |
|
* Please refer to vpu_api_legacy.cpp for normal buffer case. |
|
* Using pkt_buf buffer here is just for simplifing demo. |
|
*/ |
|
mpp_packet_init_with_buffer(&packet, this->pkt_buf); |
|
/* NOTE: It is important to clear output packet length!! */ |
|
mpp_packet_set_length(packet, 0); |
|
|
|
ret = mpp_mpi->control(mpp_ctx, MPP_ENC_GET_HDR_SYNC, packet); |
|
if (ret) { |
|
LOGD("mpi control enc get extra info failed\n"); |
|
return -1; |
|
} else { |
|
/* get and write sps/pps for H.264 */ |
|
|
|
void *ptr = mpp_packet_get_pos(packet); |
|
size_t len = mpp_packet_get_length(packet); |
|
|
|
memcpy(out_ptr, ptr, len); |
|
out_ptr = (char*)(out_ptr) + len; |
|
out_len += len; |
|
} |
|
|
|
mpp_packet_deinit(&packet); |
|
} |
|
return out_len; |
|
} |
|
|
|
int MppEncoder::Encode(void* mpp_buf, char* enc_buf, int max_size) { |
|
MPP_RET ret; |
|
void* out_ptr = enc_buf; |
|
size_t out_len = 0; |
|
|
|
MppMeta meta = NULL; |
|
MppFrame frame = NULL; |
|
MppPacket packet = NULL; |
|
// void *buf = mpp_buffer_get_ptr(this->frm_buf); |
|
// RK_S32 cam_frm_idx = -1; |
|
// MppBuffer cam_buf = NULL; |
|
RK_U32 eoi = 1; |
|
RK_U32 frm_eos = 0; |
|
|
|
ret = mpp_frame_init(&frame); |
|
if (ret) { |
|
LOGD("mpp_frame_init failed\n"); |
|
return -1; |
|
} |
|
|
|
mpp_frame_set_width(frame, enc_params.width); |
|
mpp_frame_set_height(frame, enc_params.height); |
|
mpp_frame_set_hor_stride(frame, enc_params.hor_stride); |
|
mpp_frame_set_ver_stride(frame, enc_params.ver_stride); |
|
mpp_frame_set_fmt(frame, enc_params.fmt); |
|
mpp_frame_set_eos(frame, frm_eos); |
|
mpp_frame_set_buffer(frame, mpp_buf); |
|
|
|
meta = mpp_frame_get_meta(frame); |
|
mpp_packet_init_with_buffer(&packet, pkt_buf); |
|
/* NOTE: It is important to clear output packet length!! */ |
|
mpp_packet_set_length(packet, 0); |
|
mpp_meta_set_packet(meta, KEY_OUTPUT_PACKET, packet); |
|
mpp_meta_set_buffer(meta, KEY_MOTION_INFO, this->md_info); |
|
|
|
#if 0 |
|
if (enc_params.osd_enable || enc_params.user_data_enable || enc_params.roi_enable) { |
|
if (enc_params.user_data_enable) { |
|
MppEncUserData user_data; |
|
char *str = "this is user data\n"; |
|
|
|
if ((enc_params.frame_count & 10) == 0) { |
|
user_data.pdata = str; |
|
user_data.len = strlen(str) + 1; |
|
mpp_meta_set_ptr(meta, KEY_USER_DATA, &user_data); |
|
} |
|
static RK_U8 uuid_debug_info[16] = { |
|
0x57, 0x68, 0x97, 0x80, 0xe7, 0x0c, 0x4b, 0x65, |
|
0xa9, 0x06, 0xae, 0x29, 0x94, 0x11, 0xcd, 0x9a |
|
}; |
|
|
|
MppEncUserDataSet data_group; |
|
MppEncUserDataFull datas[2]; |
|
char *str1 = "this is user data 1\n"; |
|
char *str2 = "this is user data 2\n"; |
|
data_group.count = 2; |
|
datas[0].len = strlen(str1) + 1; |
|
datas[0].pdata = str1; |
|
datas[0].uuid = uuid_debug_info; |
|
|
|
datas[1].len = strlen(str2) + 1; |
|
datas[1].pdata = str2; |
|
datas[1].uuid = uuid_debug_info; |
|
|
|
data_group.datas = datas; |
|
|
|
mpp_meta_set_ptr(meta, KEY_USER_DATAS, &data_group); |
|
} |
|
|
|
if (enc_params.osd_enable) { |
|
/* gen and cfg osd plt */ |
|
mpi_enc_gen_osd_plt(&enc_params.osd_plt, enc_params.frame_count); |
|
|
|
enc_params.osd_plt_cfg.change = MPP_ENC_OSD_PLT_CFG_CHANGE_ALL; |
|
enc_params.osd_plt_cfg.type = MPP_ENC_OSD_PLT_TYPE_USERDEF; |
|
enc_params.osd_plt_cfg.plt = &enc_params.osd_plt; |
|
|
|
ret = mpp_mpi->control(mpp_ctx, MPP_ENC_SET_OSD_PLT_CFG, &enc_params.osd_plt_cfg); |
|
if (ret) { |
|
LOGD("mpi control enc set osd plt failed ret %d\n", ret); |
|
goto RET; |
|
} |
|
|
|
/* gen and cfg osd plt */ |
|
mpi_enc_gen_osd_data(&enc_params.osd_data, enc_params.buf_grp, enc_params.width, |
|
enc_params.height, enc_params.frame_count); |
|
mpp_meta_set_ptr(meta, KEY_OSD_DATA, (void*)&enc_params.osd_data); |
|
} |
|
|
|
if (enc_params.roi_enable) { |
|
RoiRegionCfg *region = &enc_params.roi_region; |
|
|
|
/* calculated in pixels */ |
|
region->x = MPP_ALIGN(enc_params.width / 8, 16); |
|
region->y = MPP_ALIGN(enc_params.height / 8, 16); |
|
region->w = 128; |
|
region->h = 256; |
|
region->force_intra = 0; |
|
region->qp_mode = 1; |
|
region->qp_val = 24; |
|
|
|
mpp_enc_roi_add_region(enc_params.roi_mpp_ctx, region); |
|
|
|
region->x = MPP_ALIGN(enc_params.width / 2, 16); |
|
region->y = MPP_ALIGN(enc_params.height / 4, 16); |
|
region->w = 256; |
|
region->h = 128; |
|
region->force_intra = 1; |
|
region->qp_mode = 1; |
|
region->qp_val = 10; |
|
|
|
mpp_enc_roi_add_region(enc_params.roi_mpp_ctx, region); |
|
|
|
/* send roi info by metadata */ |
|
mpp_enc_roi_setup_meta(enc_params.roi_mpp_ctx, meta); |
|
} |
|
} |
|
#endif |
|
|
|
/* |
|
* NOTE: in non-block mode the frame can be resent. |
|
* The default input timeout mode is block. |
|
* |
|
* User should release the input frame to meet the requirements of |
|
* resource creator must be the resource destroyer. |
|
*/ |
|
ret = mpp_mpi->encode_put_frame(mpp_ctx, frame); |
|
mpp_frame_deinit(&frame); |
|
|
|
if (ret) { |
|
LOGD("chn %d encode put frame failed\n", chn); |
|
return -1; |
|
} |
|
|
|
do { |
|
ret = mpp_mpi->encode_get_packet(mpp_ctx, &packet); |
|
if (ret) { |
|
LOGD("chn %d encode get packet failed\n", chn); |
|
return -1; |
|
} |
|
|
|
// mpp_assert(packet); |
|
|
|
if (packet) { |
|
// write packet to file here |
|
void *ptr = mpp_packet_get_pos(packet); |
|
size_t len = mpp_packet_get_length(packet); |
|
char log_buf[256]; |
|
RK_S32 log_size = sizeof(log_buf) - 1; |
|
RK_S32 log_len = 0; |
|
|
|
// if (!enc_params.first_pkt) |
|
// enc_params.first_pkt = mpp_time(); |
|
|
|
RK_U32 pkt_eos = mpp_packet_get_eos(packet); |
|
|
|
/* set encode result */ |
|
if (this->callback != nullptr) { |
|
this->callback(this->userdata, (const char*)ptr, len); |
|
} |
|
if (enc_buf != nullptr && max_size > 0) { |
|
if (out_len + log_len < max_size) { |
|
memcpy(out_ptr, ptr, len); |
|
out_len += len; |
|
out_ptr = (char*)out_ptr + len; |
|
} else { |
|
LOGE("error enc_buf no enought"); |
|
} |
|
} |
|
|
|
// log_len += snprintf(log_buf + log_len, log_size - log_len, |
|
// "encoded frame %-4d", enc_params.frame_count); |
|
|
|
/* for low delay partition encoding */ |
|
if (mpp_packet_is_partition(packet)) { |
|
eoi = mpp_packet_is_eoi(packet); |
|
|
|
// log_len += snprintf(log_buf + log_len, log_size - log_len, |
|
// " pkt %d", enc_params.frm_pkt_cnt); |
|
// enc_params.frm_pkt_cnt = (eoi) ? (0) : (enc_params.frm_pkt_cnt + 1); |
|
} |
|
|
|
log_len += snprintf(log_buf + log_len, log_size - log_len, |
|
" size %-7zu", len); |
|
|
|
if (mpp_packet_has_meta(packet)) { |
|
meta = mpp_packet_get_meta(packet); |
|
RK_S32 temporal_id = 0; |
|
RK_S32 lt_idx = -1; |
|
RK_S32 avg_qp = -1; |
|
|
|
if (MPP_OK == mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id)) |
|
log_len += snprintf(log_buf + log_len, log_size - log_len, |
|
" tid %d", temporal_id); |
|
|
|
if (MPP_OK == mpp_meta_get_s32(meta, KEY_LONG_REF_IDX, <_idx)) |
|
log_len += snprintf(log_buf + log_len, log_size - log_len, |
|
" lt %d", lt_idx); |
|
|
|
if (MPP_OK == mpp_meta_get_s32(meta, KEY_ENC_AVERAGE_QP, &avg_qp)) |
|
log_len += snprintf(log_buf + log_len, log_size - log_len, |
|
" qp %d", avg_qp); |
|
} |
|
|
|
LOGD("chn %d %s\n", chn, log_buf); |
|
|
|
mpp_packet_deinit(&packet); |
|
|
|
// enc_params.stream_size += len; |
|
// enc_params.frame_count += eoi; |
|
|
|
// if (enc_params.pkt_eos) { |
|
// LOGD("chn %d found last packet\n", chn); |
|
// mpp_assert(enc_params.frm_eos); |
|
// } |
|
} |
|
} while (!eoi); |
|
|
|
// if (enc_params.frm_eos && enc_params.pkt_eos) |
|
// break; |
|
return out_len; |
|
} |
|
|
|
int MppEncoder::Reset() { |
|
if (mpp_mpi != NULL) { |
|
mpp_mpi->reset(mpp_ctx); |
|
} |
|
return 0; |
|
} |
|
|
|
size_t MppEncoder::GetFrameSize() { |
|
return this->frame_size; |
|
} |
|
|
|
void* MppEncoder::ImportBuffer(int index, size_t size, int fd, int type) { |
|
MppBuffer buf; |
|
MppBufferInfo info; |
|
memset(&info, 0, sizeof(MppBufferInfo)); |
|
info.type = (MppBufferType)type; // MPP_BUFFER_TYPE_EXT_DMA |
|
info.fd = fd; |
|
info.size = size; |
|
info.index = index; |
|
mpp_buffer_import(&buf, &info); |
|
return buf; |
|
} |
|
|
|
void* MppEncoder::GetInputFrameBuffer() { |
|
int ret; |
|
if (this->frm_buf == nullptr) { |
|
ret = mpp_buffer_get(this->buf_grp, &this->frm_buf, this->frame_size); |
|
if (ret) { |
|
LOGD("failed to get buffer for input frame ret %d\n", ret); |
|
return NULL; |
|
} |
|
} |
|
return this->frm_buf; |
|
} |
|
|
|
int MppEncoder::GetInputFrameBufferFd(void* mpp_buffer) { |
|
return mpp_buffer_get_fd(mpp_buffer); |
|
} |
|
|
|
void* MppEncoder::GetInputFrameBufferAddr(void* mpp_buffer) { |
|
return mpp_buffer_get_ptr(mpp_buffer); |
|
} |