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:
parent
6b1f61949b
commit
5e9b2d6322
@ -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, ¶ms);
|
||||
|
||||
err = nv.nvEncEncodePicture(enc->session, ¶ms);
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user