diff --git a/libavcodec/rkmppenc.c b/libavcodec/rkmppenc.c index 704d0d9828..c3ff07deb0 100644 --- a/libavcodec/rkmppenc.c +++ b/libavcodec/rkmppenc.c @@ -182,6 +182,9 @@ static void clear_unused_frames(MPPEncFrame *list) mpp_frame_deinit(&list->mpp_frame); list->mpp_frame = NULL; + av_freep(&list->mpp_sei); + list->mpp_sei_sz = 0; + av_frame_free(&list->frame); list->queued = 0; } @@ -211,6 +214,9 @@ static void clear_frame_list(MPPEncFrame **list) frame->mpp_frame = NULL; } + av_freep(&frame->mpp_sei); + frame->mpp_sei_sz = 0; + av_frame_free(&frame->frame); av_freep(&frame); } @@ -492,6 +498,8 @@ static int rkmpp_set_enc_cfg(AVCodecContext *avctx) mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", (r->dct8x8 && avctx->profile == AV_PROFILE_H264_HIGH)); + mpp_enc_cfg_set_s32(cfg, "h264:prefix_mode", r->prefix_mode); + switch (avctx->profile) { case AV_PROFILE_H264_BASELINE: av_log(avctx, AV_LOG_VERBOSE, "Profile is set to BASELINE\n"); break; @@ -541,7 +549,7 @@ static int rkmpp_set_enc_cfg(AVCodecContext *avctx) if (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_HEVC) { - sei_mode = MPP_ENC_SEI_MODE_DISABLE; + sei_mode = r->udu_sei ? MPP_ENC_SEI_MODE_ONE_FRAME : MPP_ENC_SEI_MODE_DISABLE; if ((ret = r->mapi->control(r->mctx, MPP_ENC_SET_SEI_CFG, &sei_mode)) != MPP_OK) { av_log(avctx, AV_LOG_ERROR, "Failed to set SEI config: %d\n", ret); return AVERROR_EXTERNAL; @@ -558,6 +566,70 @@ static int rkmpp_set_enc_cfg(AVCodecContext *avctx) return 0; } +static int rkmpp_prepare_udu_sei_data(AVCodecContext *avctx, MPPEncFrame *mpp_enc_frame) +{ + int i, ret, sei_count = 0; + + if (!mpp_enc_frame || + !mpp_enc_frame->frame || + !mpp_enc_frame->mpp_frame) + return AVERROR(EINVAL); + + /* user data unregistered SEI of H26X */ + for (i = 0; i < mpp_enc_frame->frame->nb_side_data; i++) { + AVFrameSideData *sd = mpp_enc_frame->frame->side_data[i]; + uint8_t *user_data = sd->data; + void *buf = NULL; + + if (sd->type != AV_FRAME_DATA_SEI_UNREGISTERED) + continue; + + if (sd->size < AV_UUID_LEN) { + av_log(avctx, AV_LOG_WARNING, "Invalid UDU SEI data: " + "(%"SIZE_SPECIFIER" < UUID(%d-bytes)), skipping\n", + sd->size, AV_UUID_LEN); + continue; + } + + buf = av_fast_realloc(mpp_enc_frame->mpp_sei, + &mpp_enc_frame->mpp_sei_sz, + (sei_count + 1) * sizeof(*(mpp_enc_frame->mpp_sei))); + if (!buf) { + av_log(avctx, AV_LOG_ERROR, "Failed to realloc UDU SEI buffer\n"); + return AVERROR(ENOMEM); + } else { + mpp_enc_frame->mpp_sei = buf; + + mpp_enc_frame->mpp_sei[sei_count].len = sd->size - AV_UUID_LEN; + mpp_enc_frame->mpp_sei[sei_count].uuid = (RK_U8 *)user_data; + mpp_enc_frame->mpp_sei[sei_count].pdata = &user_data[AV_UUID_LEN]; + + ++sei_count; + } + } + + if (sei_count > 0) { + MppMeta mpp_meta = NULL; + MppEncUserDataSet *mpp_sei_set = &mpp_enc_frame->mpp_sei_set; + + mpp_sei_set->datas = mpp_enc_frame->mpp_sei; + mpp_sei_set->count = sei_count; + + mpp_meta = mpp_frame_get_meta(mpp_enc_frame->mpp_frame); + if (!mpp_meta) { + av_log(avctx, AV_LOG_ERROR, "Failed to get frame meta\n"); + return AVERROR_EXTERNAL; + } + if ((ret = mpp_meta_set_ptr(mpp_meta, KEY_USER_DATAS, + mpp_sei_set)) != MPP_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set the UDU SEI datas ptr\n"); + return AVERROR_EXTERNAL; + } + } + + return 0; +} + static MPPEncFrame *rkmpp_submit_frame(AVCodecContext *avctx, AVFrame *frame) { RKMPPEncContext *r = avctx->priv_data; @@ -728,6 +800,14 @@ static MPPEncFrame *rkmpp_submit_frame(AVCodecContext *avctx, AVFrame *frame) mpp_frame_set_buffer(mpp_frame, mpp_buf); mpp_frame_set_buf_size(mpp_frame, drm_desc->objects[0].size); + if (r->udu_sei && + (avctx->codec_id == AV_CODEC_ID_H264 || + avctx->codec_id == AV_CODEC_ID_HEVC)) { + ret = rkmpp_prepare_udu_sei_data(avctx, mpp_enc_frame); + if (ret < 0) + goto exit; + } + return mpp_enc_frame; exit: diff --git a/libavcodec/rkmppenc.h b/libavcodec/rkmppenc.h index d7f046fad4..80c9d3500f 100644 --- a/libavcodec/rkmppenc.h +++ b/libavcodec/rkmppenc.h @@ -37,6 +37,7 @@ #include "libavutil/hwcontext_rkmpp.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "libavutil/uuid.h" #define H26X_HEADER_SIZE 1024 #define H26X_ASYNC_FRAMES 4 @@ -46,6 +47,9 @@ typedef struct MPPEncFrame { AVFrame *frame; MppFrame mpp_frame; + MppEncUserDataSet mpp_sei_set; + MppEncUserDataFull *mpp_sei; + int mpp_sei_sz; struct MPPEncFrame *next; int queued; } MPPEncFrame; @@ -78,6 +82,8 @@ typedef struct RKMPPEncContext { int level; int coder; int dct8x8; + int udu_sei; + int prefix_mode; } RKMPPEncContext; static const AVRational mpp_tb = { 1, 1000000 }; @@ -143,6 +149,10 @@ static const AVOption h264_options[] = { { "cabac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "coder" }, { "8x8dct", "Set the high profile 8x8 transform", OFFSET(dct8x8), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE, "8x8dct" }, + { "udu_sei", "Pass on user data unregistered SEI if available", OFFSET(udu_sei), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, VE, "udu_sei" }, + { "prefix_mode", "Add prefix NAL between SEI info and encoded bitstream data", OFFSET(prefix_mode), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, VE, "prefix_mode" }, { NULL }, }; @@ -170,6 +180,8 @@ static const AVOption hevc_options[] = { { "6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 180 }, 0, 0, VE, "level" }, { "6.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 183 }, 0, 0, VE, "level" }, { "6.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 186 }, 0, 0, VE, "level" }, + { "udu_sei", "Pass on user data unregistered SEI if available", OFFSET(udu_sei), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, VE, "udu_sei" }, { NULL }, };