// Copyright 2019 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "mpp_inc.h" #include #include "media_config.h" #include "media_type.h" #include "utils.h" namespace easymedia { MppFrameFormat ConvertToMppPixFmt(const PixelFormat& fmt) { // static const MppFrameFormat invalid_mpp_fmt = // static_cast(-1); static_assert(PIX_FMT_YUV420P == 0, "The index should greater than 0\n"); static MppFrameFormat mpp_fmts[PIX_FMT_NB] = { [PIX_FMT_YUV420P] = MPP_FMT_YUV420P, [PIX_FMT_NV12] = MPP_FMT_YUV420SP, [PIX_FMT_NV21] = MPP_FMT_YUV420SP_VU, [PIX_FMT_YUV422P] = MPP_FMT_YUV422P, [PIX_FMT_NV16] = MPP_FMT_YUV422SP, [PIX_FMT_NV61] = MPP_FMT_YUV422SP_VU, [PIX_FMT_YUYV422] = MPP_FMT_YUV422_YUYV, [PIX_FMT_UYVY422] = MPP_FMT_YUV422_UYVY, [PIX_FMT_RGB332] = (MppFrameFormat)-1, [PIX_FMT_RGB565] = MPP_FMT_RGB565, [PIX_FMT_BGR565] = MPP_FMT_BGR565, [PIX_FMT_RGB888] = MPP_FMT_RGB888, [PIX_FMT_BGR888] = MPP_FMT_BGR888, [PIX_FMT_ARGB8888] = MPP_FMT_ARGB8888, [PIX_FMT_ABGR8888] = MPP_FMT_ABGR8888, [PIX_FMT_FBC0] = (MppFrameFormat)(MPP_FMT_YUV420SP | MPP_FRAME_FBC_AFBC_V1), [PIX_FMT_FBC2] = (MppFrameFormat)(MPP_FMT_YUV422SP | MPP_FRAME_FBC_AFBC_V1)}; if (fmt >= 0 && fmt < PIX_FMT_NB) { return mpp_fmts[fmt]; } return (MppFrameFormat)-1; } PixelFormat ConvertToPixFmt(const MppFrameFormat& mfmt) { switch (mfmt) { case MPP_FMT_YUV420P: return PIX_FMT_YUV420P; case MPP_FMT_YUV420SP: return PIX_FMT_NV12; case MPP_FMT_YUV420SP_VU: return PIX_FMT_NV21; case MPP_FMT_YUV422P: return PIX_FMT_YUV422P; case MPP_FMT_YUV422SP: return PIX_FMT_NV16; case MPP_FMT_YUV422SP_VU: return PIX_FMT_NV61; case MPP_FMT_YUV422_YUYV: return PIX_FMT_YUYV422; case MPP_FMT_YUV422_UYVY: return PIX_FMT_UYVY422; case MPP_FMT_RGB565: return PIX_FMT_RGB565; case MPP_FMT_BGR565: return PIX_FMT_BGR565; case MPP_FMT_RGB888: return PIX_FMT_RGB888; case MPP_FMT_BGR888: return PIX_FMT_BGR888; case MPP_FMT_ARGB8888: return PIX_FMT_ARGB8888; case MPP_FMT_ABGR8888: return PIX_FMT_ABGR8888; default: LOG("unsupport for mpp pixel fmt: %d\n", mfmt); return PIX_FMT_NONE; } } class _MPP_SUPPORT_TYPES : public SupportMediaTypes { public: _MPP_SUPPORT_TYPES() { types.append(TYPENEAR(IMAGE_YUV420P)); types.append(TYPENEAR(IMAGE_NV12)); types.append(TYPENEAR(IMAGE_NV21)); types.append(TYPENEAR(IMAGE_YUV422P)); types.append(TYPENEAR(IMAGE_NV16)); types.append(TYPENEAR(IMAGE_NV61)); types.append(TYPENEAR(IMAGE_YUYV422)); types.append(TYPENEAR(IMAGE_UYVY422)); types.append(TYPENEAR(IMAGE_RGB565)); types.append(TYPENEAR(IMAGE_BGR565)); types.append(TYPENEAR(IMAGE_RGB888)); types.append(TYPENEAR(IMAGE_BGR888)); types.append(TYPENEAR(IMAGE_ARGB8888)); types.append(TYPENEAR(IMAGE_ABGR8888)); types.append(TYPENEAR(IMAGE_FBC0)); types.append(TYPENEAR(IMAGE_FBC2)); } }; static _MPP_SUPPORT_TYPES priv_types; const char* MppAcceptImageFmts() { return priv_types.types.c_str(); } MppCodingType GetMPPCodingType(const std::string& data_type) { if (data_type == VIDEO_H264) { return MPP_VIDEO_CodingAVC; } else if (data_type == VIDEO_H265) { return MPP_VIDEO_CodingHEVC; } else if (data_type == VIDEO_MJPEG) { return MPP_VIDEO_CodingMJPEG; } else if (data_type == IMAGE_JPEG) { return MPP_VIDEO_CodingMJPEG; } LOG("mpp decoder TODO for %s\n", data_type.c_str()); return MPP_VIDEO_CodingUnused; } static MppEncRcQuality mpp_rc_qualitys[] = { MPP_ENC_RC_QUALITY_WORST, MPP_ENC_RC_QUALITY_WORSE, MPP_ENC_RC_QUALITY_MEDIUM, MPP_ENC_RC_QUALITY_BETTER, MPP_ENC_RC_QUALITY_BEST, MPP_ENC_RC_QUALITY_CQP, MPP_ENC_RC_QUALITY_AQ_ONLY}; MppEncRcQuality GetMPPRCQuality(const char* quality) { static_assert(ARRAY_ELEMS(rc_quality_strings) == ARRAY_ELEMS(mpp_rc_qualitys), "rc quality strings miss match mpp rc quality enum"); if (!quality) { return MPP_ENC_RC_QUALITY_BUTT; } for (size_t i = 0; i < ARRAY_ELEMS(rc_quality_strings); i++) if (!strcasecmp(quality, rc_quality_strings[i])) { return mpp_rc_qualitys[i]; } return MPP_ENC_RC_QUALITY_BUTT; } static const MppEncRcMode mpp_rc_modes[] = {MPP_ENC_RC_MODE_VBR, MPP_ENC_RC_MODE_CBR, MPP_ENC_RC_MODE_FIXQP}; MppEncRcMode GetMPPRCMode(const char* rc_mode) { static_assert(ARRAY_ELEMS(rc_mode_strings) == ARRAY_ELEMS(mpp_rc_modes), "rc mode strings miss match mpp rc mode enum"); if (!rc_mode) { return MPP_ENC_RC_MODE_BUTT; } for (size_t i = 0; i < ARRAY_ELEMS(rc_mode_strings); i++) if (!strcasecmp(rc_mode, rc_mode_strings[i])) { return mpp_rc_modes[i]; } return MPP_ENC_RC_MODE_BUTT; } MPPContext::MPPContext() : ctx(NULL), mpi(NULL), frame_group(NULL) { } MPPContext::~MPPContext() { if (mpi) { mpi->reset(ctx); mpp_destroy(ctx); ctx = NULL; LOG("mpp destroy ctx done\n"); } if (frame_group) { mpp_buffer_group_put(frame_group); frame_group = NULL; LOG("mpp buffer group free done\n"); } } MPP_RET init_mpp_buffer(MppBuffer& buffer, const std::shared_ptr& mb, size_t frame_size) { MPP_RET ret; int fd = mb->GetFD(); void* ptr = mb->GetPtr(); size_t size = mb->GetValidSize(); if (fd >= 0) { MppBufferInfo info; memset(&info, 0, sizeof(info)); info.type = MPP_BUFFER_TYPE_ION; info.size = size; info.fd = fd; info.ptr = ptr; ret = mpp_buffer_import(&buffer, &info); if (ret) { LOG("import input picture buffer failed\n"); goto fail; } } else { if (frame_size == 0) { return MPP_OK; } if (size == 0) { size = frame_size; assert(frame_size > 0); } ret = mpp_buffer_get(NULL, &buffer, size); if (ret) { LOG("allocate output stream buffer failed\n"); goto fail; } } return MPP_OK; fail: if (buffer) { mpp_buffer_put(buffer); buffer = nullptr; } return ret; } MPP_RET init_mpp_buffer_with_content(MppBuffer& buffer, const std::shared_ptr& mb) { size_t size = mb->GetValidSize(); MPP_RET ret = init_mpp_buffer(buffer, mb, size); if (ret) { return ret; } int fd = mb->GetFD(); void* ptr = mb->GetPtr(); // As init_mpp_buffer is a no time-consuming function and do not memcpy // content to a virtual buffer, do memcpy here. if (fd < 0 && ptr) { // !!time-consuming operation // LOGD("extra time-consuming memcpy to mpp, size=%d!\n", size); memcpy(mpp_buffer_get_ptr(buffer), ptr, size); // sync between cpu and device if cached? } return MPP_OK; } // vi_len: virtual Intra frame gap. // gop_len: should equal gop_size. MPP_RET mpi_enc_gen_ref_cfg(MppEncRefCfg ref, RK_S32 gop_mode, RK_S32 gop_len, RK_S32 vi_len) { MppEncRefLtFrmCfg lt_ref[4]; MppEncRefStFrmCfg st_ref[16]; RK_S32 lt_cnt = 0; RK_S32 st_cnt = 0; MPP_RET ret = MPP_OK; memset(<_ref, 0, sizeof(lt_ref)); memset(&st_ref, 0, sizeof(st_ref)); switch (gop_mode) { case GOP_MODE_TSVC4: { // tsvc4 // /-> P1 /-> P3 /-> P5 /-> P7 // / / / / // //--------> P2 //--------> P6 // // // // ///---------------------> P4 // /// // P0 ------------------------------------------------> P8 lt_cnt = 1; /* set 8 frame lt-ref gap */ lt_ref[0].lt_idx = 0; lt_ref[0].temporal_id = 0; lt_ref[0].ref_mode = REF_TO_PREV_LT_REF; lt_ref[0].lt_gap = 8; lt_ref[0].lt_delay = 0; st_cnt = 9; /* set tsvc4 st-ref struct */ /* st 0 layer 0 - ref */ st_ref[0].is_non_ref = 0; st_ref[0].temporal_id = 0; st_ref[0].ref_mode = REF_TO_TEMPORAL_LAYER; st_ref[0].ref_arg = 0; st_ref[0].repeat = 0; /* st 1 layer 3 - non-ref */ st_ref[1].is_non_ref = 1; st_ref[1].temporal_id = 3; st_ref[1].ref_mode = REF_TO_PREV_REF_FRM; st_ref[1].ref_arg = 0; st_ref[1].repeat = 0; /* st 2 layer 2 - ref */ st_ref[2].is_non_ref = 0; st_ref[2].temporal_id = 2; st_ref[2].ref_mode = REF_TO_PREV_REF_FRM; st_ref[2].ref_arg = 0; st_ref[2].repeat = 0; /* st 3 layer 3 - non-ref */ st_ref[3].is_non_ref = 1; st_ref[3].temporal_id = 3; st_ref[3].ref_mode = REF_TO_PREV_REF_FRM; st_ref[3].ref_arg = 0; st_ref[3].repeat = 0; /* st 4 layer 1 - ref */ st_ref[4].is_non_ref = 0; st_ref[4].temporal_id = 1; st_ref[4].ref_mode = REF_TO_PREV_LT_REF; st_ref[4].ref_arg = 0; st_ref[4].repeat = 0; /* st 5 layer 3 - non-ref */ st_ref[5].is_non_ref = 1; st_ref[5].temporal_id = 3; st_ref[5].ref_mode = REF_TO_PREV_REF_FRM; st_ref[5].ref_arg = 0; st_ref[5].repeat = 0; /* st 6 layer 2 - ref */ st_ref[6].is_non_ref = 0; st_ref[6].temporal_id = 2; st_ref[6].ref_mode = REF_TO_PREV_REF_FRM; st_ref[6].ref_arg = 0; st_ref[6].repeat = 0; /* st 7 layer 3 - non-ref */ st_ref[7].is_non_ref = 1; st_ref[7].temporal_id = 3; st_ref[7].ref_mode = REF_TO_PREV_REF_FRM; st_ref[7].ref_arg = 0; st_ref[7].repeat = 0; /* st 8 layer 0 - ref */ st_ref[8].is_non_ref = 0; st_ref[8].temporal_id = 0; st_ref[8].ref_mode = REF_TO_TEMPORAL_LAYER; st_ref[8].ref_arg = 0; st_ref[8].repeat = 0; } break; case GOP_MODE_TSVC3: { // tsvc3 // /-> P1 /-> P3 // / / // //--------> P2 // // // P0/---------------------> P4 lt_cnt = 0; st_cnt = 5; /* set tsvc4 st-ref struct */ /* st 0 layer 0 - ref */ st_ref[0].is_non_ref = 0; st_ref[0].temporal_id = 0; st_ref[0].ref_mode = REF_TO_TEMPORAL_LAYER; st_ref[0].ref_arg = 0; st_ref[0].repeat = 0; /* st 1 layer 2 - non-ref */ st_ref[1].is_non_ref = 1; st_ref[1].temporal_id = 2; st_ref[1].ref_mode = REF_TO_PREV_REF_FRM; st_ref[1].ref_arg = 0; st_ref[1].repeat = 0; /* st 2 layer 1 - ref */ st_ref[2].is_non_ref = 0; st_ref[2].temporal_id = 1; st_ref[2].ref_mode = REF_TO_PREV_REF_FRM; st_ref[2].ref_arg = 0; st_ref[2].repeat = 0; /* st 3 layer 2 - non-ref */ st_ref[3].is_non_ref = 1; st_ref[3].temporal_id = 2; st_ref[3].ref_mode = REF_TO_PREV_REF_FRM; st_ref[3].ref_arg = 0; st_ref[3].repeat = 0; /* st 4 layer 0 - ref */ st_ref[4].is_non_ref = 0; st_ref[4].temporal_id = 0; st_ref[4].ref_mode = REF_TO_TEMPORAL_LAYER; st_ref[4].ref_arg = 0; st_ref[4].repeat = 0; } break; case GOP_MODE_TSVC2: { // tsvc2 // /-> P1 // / // P0--------> P2 lt_cnt = 0; st_cnt = 3; /* set tsvc4 st-ref struct */ /* st 0 layer 0 - ref */ st_ref[0].is_non_ref = 0; st_ref[0].temporal_id = 0; st_ref[0].ref_mode = REF_TO_TEMPORAL_LAYER; st_ref[0].ref_arg = 0; st_ref[0].repeat = 0; /* st 1 layer 2 - non-ref */ st_ref[1].is_non_ref = 1; st_ref[1].temporal_id = 1; st_ref[1].ref_mode = REF_TO_PREV_REF_FRM; st_ref[1].ref_arg = 0; st_ref[1].repeat = 0; /* st 2 layer 1 - ref */ st_ref[2].is_non_ref = 0; st_ref[2].temporal_id = 0; st_ref[2].ref_mode = REF_TO_PREV_REF_FRM; st_ref[2].ref_arg = 0; st_ref[2].repeat = 0; } break; case GOP_MODE_SMARTP: { // smartp: M = vi_len - 2; N = gop_size. // /-> E0 -> E1...-> EM /-> E0 -> E1...-> EM /-> E0 -> E1...-> EM // / / / // P0-------------------> P1 / // |---------------------------------------------> P2 // |------------------------------------------------------------------------> // PN lt_cnt = 1; st_cnt = 3; /* set gop_len frame lt-ref gap */ lt_ref[0].lt_idx = 0; lt_ref[0].temporal_id = 0; lt_ref[0].ref_mode = REF_TO_PREV_LT_REF; lt_ref[0].lt_gap = gop_len; lt_ref[0].lt_delay = 0; /* set smartp st-ref struct */ /* st 0 layer 0 - ref */ st_ref[0].is_non_ref = 0; st_ref[0].temporal_id = 0; st_ref[0].ref_mode = REF_TO_PREV_INTRA; st_ref[0].ref_arg = 0; st_ref[0].repeat = 0; /* st 1 layer 1 - non-ref */ st_ref[1].is_non_ref = 0; st_ref[1].temporal_id = 1; st_ref[1].ref_mode = REF_TO_PREV_REF_FRM; st_ref[1].ref_arg = 0; st_ref[1].repeat = vi_len - 2; /* st 2 layer 0 - ref */ st_ref[2].is_non_ref = 0; st_ref[2].temporal_id = 0; st_ref[2].ref_mode = REF_TO_PREV_INTRA; st_ref[2].ref_arg = 0; st_ref[2].repeat = 0; } break; default: { LOG("ERROR: MPP: unsupport gop mode %d\n", gop_mode); } break; } #if 0 for(int i = 0; i < lt_cnt; i++) { printf("\nLT ref[%d].lt_idx = %d\n", i, lt_ref[i].lt_idx); printf("LT ref[%d].temporal_id = %d\n", i, lt_ref[i].temporal_id); printf("LT ref[%d].ref_mode = %d\n", i, lt_ref[i].ref_mode); printf("LT ref[%d].lt_gap = %d\n", i, lt_ref[i].lt_gap); printf("LT ref[%d].lt_delay = %d\n", i, lt_ref[i].lt_delay); } for(int i = 0; i < st_cnt; i++) { printf("\nST ref[%d].is_non_ref = %d\n", i, st_ref[i].is_non_ref); printf("ST ref[%d].temporal_id = %d\n", i, st_ref[i].temporal_id); printf("ST ref[%d].ref_mode = %d\n", i, st_ref[i].ref_mode); printf("ST ref[%d].ref_arg = %d\n", i, st_ref[i].ref_arg); printf("ST ref[%d].repeat = %d\n", i, st_ref[i].repeat); } #endif if (lt_cnt || st_cnt) { ret = mpp_enc_ref_cfg_set_cfg_cnt(ref, lt_cnt, st_cnt); if (lt_cnt) { ret = mpp_enc_ref_cfg_add_lt_cfg(ref, lt_cnt, lt_ref); } if (st_cnt) { ret = mpp_enc_ref_cfg_add_st_cfg(ref, st_cnt, st_ref); } /* check and get dpb size */ ret = mpp_enc_ref_cfg_check(ref); } return ret; } } // namespace easymedia