0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-19 20:32:15 +02:00

obs-ffmpeg: Add ROI support for native NVENC

This commit is contained in:
Rodney 2023-12-24 10:14:39 +01:00 committed by derrod
parent 6b1f61949b
commit 5e9b2d6322

View File

@ -126,6 +126,10 @@ struct nvenc_data {
uint8_t *sei;
size_t sei_size;
int8_t *roi_map;
size_t roi_map_size;
uint32_t roi_increment;
};
/* ------------------------------------------------------------------------- */
@ -680,6 +684,7 @@ static bool init_encoder_base(struct nvenc_data *enc, obs_data_t *settings,
config->rcParams.maxBitRate = vbr ? max_bitrate * 1000 : bitrate * 1000;
config->rcParams.vbvBufferSize = bitrate * 1000;
config->rcParams.multiPass = nv_multipass;
config->rcParams.qpMapMode = NV_ENC_QP_MAP_DELTA;
/* -------------------------- */
/* initialize */
@ -1250,6 +1255,7 @@ static void nvenc_destroy(void *data)
da_free(enc->bitstreams);
da_free(enc->input_textures);
da_free(enc->packet_data);
bfree(enc->roi_map);
bfree(enc);
}
@ -1378,6 +1384,96 @@ static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
return true;
}
struct roi_params {
uint32_t mb_width;
uint32_t mb_height;
uint32_t mb_size;
bool av1;
int8_t *map;
};
static void roi_cb(void *param, struct obs_encoder_roi *roi)
{
const struct roi_params *rp = param;
int8_t qp_val;
/* AV1 has a larger QP range than HEVC/H.264 */
if (rp->av1) {
qp_val = (int8_t)(-128.0f * roi->priority);
} else {
qp_val = (int8_t)(-51.0f * roi->priority);
}
const uint32_t roi_left = roi->left / rp->mb_size;
const uint32_t roi_top = roi->top / rp->mb_size;
const uint32_t roi_right = (roi->right - 1) / rp->mb_size;
const uint32_t roi_bottom = (roi->bottom - 1) / rp->mb_size;
for (uint32_t mb_y = 0; mb_y < rp->mb_height; mb_y++) {
if (mb_y < roi_top || mb_y > roi_bottom)
continue;
for (uint32_t mb_x = 0; mb_x < rp->mb_width; mb_x++) {
if (mb_x < roi_left || mb_x > roi_right)
continue;
rp->map[mb_y * rp->mb_width + mb_x] = qp_val;
}
}
}
static void add_roi(struct nvenc_data *enc, NV_ENC_PIC_PARAMS *params)
{
const uint32_t increment = obs_encoder_get_roi_increment(enc->encoder);
if (enc->roi_map && enc->roi_increment == increment) {
params->qpDeltaMap = enc->roi_map;
params->qpDeltaMapSize = (uint32_t)enc->roi_map_size;
return;
}
uint32_t mb_size;
switch (enc->codec) {
case CODEC_H264:
/* H.264 is always 16x16 */
mb_size = 16;
break;
case CODEC_HEVC:
/* HEVC can be 16x16, 32x32, or 64x64, but NVENC is always 32x32 */
mb_size = 32;
break;
case CODEC_AV1:
/* AV1 can be 64x64 or 128x128, but NVENC is always 64x64 */
mb_size = 64;
break;
}
const uint32_t mb_width = (enc->cx + mb_size - 1) / mb_size;
const uint32_t mb_height = (enc->cy + mb_size - 1) / mb_size;
const size_t map_size = mb_width * mb_height * sizeof(int8_t);
if (map_size != enc->roi_map_size) {
enc->roi_map = brealloc(enc->roi_map, map_size);
enc->roi_map_size = map_size;
}
memset(enc->roi_map, 0, enc->roi_map_size);
struct roi_params par = {
.mb_width = mb_width,
.mb_height = mb_height,
.mb_size = mb_size,
.av1 = enc->codec == CODEC_AV1,
.map = enc->roi_map,
};
obs_encoder_enum_roi(enc->encoder, roi_cb, &par);
enc->roi_increment = increment;
params->qpDeltaMap = enc->roi_map;
params->qpDeltaMapSize = (uint32_t)map_size;
}
static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
uint64_t lock_key, uint64_t *next_key,
struct encoder_packet *packet,
@ -1450,6 +1546,10 @@ static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
params.inputPitch = enc->cx;
params.outputBitstream = bs->ptr;
/* Add ROI map if enabled */
if (obs_encoder_has_roi(enc->encoder))
add_roi(enc, &params);
err = nv.nvEncEncodePicture(enc->session, &params);
if (err != NV_ENC_SUCCESS && err != NV_ENC_ERR_NEED_MORE_INPUT) {
nv_failed(enc->encoder, err, __FUNCTION__,
@ -1534,7 +1634,8 @@ struct obs_encoder_info h264_nvenc_info = {
.id = "jim_nvenc",
.codec = "h264",
.type = OBS_ENCODER_VIDEO,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE |
OBS_ENCODER_CAP_ROI,
.get_name = h264_nvenc_get_name,
.create = h264_nvenc_create,
.destroy = nvenc_destroy,
@ -1551,7 +1652,8 @@ struct obs_encoder_info hevc_nvenc_info = {
.id = "jim_hevc_nvenc",
.codec = "hevc",
.type = OBS_ENCODER_VIDEO,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE |
OBS_ENCODER_CAP_ROI,
.get_name = hevc_nvenc_get_name,
.create = hevc_nvenc_create,
.destroy = nvenc_destroy,
@ -1568,7 +1670,8 @@ struct obs_encoder_info av1_nvenc_info = {
.id = "jim_av1_nvenc",
.codec = "av1",
.type = OBS_ENCODER_VIDEO,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE |
OBS_ENCODER_CAP_ROI,
.get_name = av1_nvenc_get_name,
.create = av1_nvenc_create,
.destroy = nvenc_destroy,