lavc/rkmppenc: add UDU SEI support for H26x encoders

Signed-off-by: nyanmisaka <nst799610810@gmail.com>
This commit is contained in:
nyanmisaka 2025-04-22 19:19:30 +08:00
parent a7817eed0b
commit 5898b091ee
2 changed files with 93 additions and 1 deletions

View file

@ -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:

View file

@ -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 },
};