mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-19 20:32:15 +02:00
obs-ffmpeg: Add ROI support to AMF
This commit is contained in:
parent
5e9b2d6322
commit
730ab5e6d1
@ -95,6 +95,7 @@ struct amf_base {
|
||||
AMFBufferPtr packet_data;
|
||||
AMFRate amf_frame_rate;
|
||||
AMFBufferPtr header;
|
||||
AMFSurfacePtr roi_map;
|
||||
|
||||
std::deque<AMFDataPtr> queued_packets;
|
||||
|
||||
@ -110,11 +111,13 @@ struct amf_base {
|
||||
uint32_t cx;
|
||||
uint32_t cy;
|
||||
uint32_t linesize = 0;
|
||||
uint32_t roi_increment = 0;
|
||||
int fps_num;
|
||||
int fps_den;
|
||||
bool full_range;
|
||||
bool bframes_supported = false;
|
||||
bool first_update = true;
|
||||
bool roi_supported = false;
|
||||
|
||||
inline amf_base(bool fallback) : fallback(fallback) {}
|
||||
virtual ~amf_base() = default;
|
||||
@ -580,6 +583,100 @@ static void convert_to_encoder_packet(amf_base *enc, AMFDataPtr &data,
|
||||
#define SEC_TO_NSEC 1000000000ULL
|
||||
#endif
|
||||
|
||||
struct roi_params {
|
||||
uint32_t mb_width;
|
||||
uint32_t mb_height;
|
||||
amf_int32 pitch;
|
||||
bool h264;
|
||||
amf_uint32 *buf;
|
||||
};
|
||||
|
||||
static void roi_cb(void *param, obs_encoder_roi *roi)
|
||||
{
|
||||
const roi_params *rp = static_cast<roi_params *>(param);
|
||||
|
||||
/* AMF does not support negative priority */
|
||||
if (roi->priority < 0)
|
||||
return;
|
||||
|
||||
const uint32_t mb_size = rp->h264 ? 16 : 64;
|
||||
const uint32_t roi_left = roi->left / mb_size;
|
||||
const uint32_t roi_top = roi->top / mb_size;
|
||||
const uint32_t roi_right = (roi->right - 1) / mb_size;
|
||||
const uint32_t roi_bottom = (roi->bottom - 1) / mb_size;
|
||||
/* Importance value range is 0..10 */
|
||||
const amf_uint32 priority = (amf_uint32)(10.0f * roi->priority);
|
||||
|
||||
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->buf[mb_y * rp->pitch / sizeof(amf_uint32) + mb_x] =
|
||||
priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void create_roi(amf_base *enc, AMFSurface *amf_surf)
|
||||
{
|
||||
uint32_t mb_size = 16; /* H.264 is always 16x16 */
|
||||
if (enc->codec == amf_codec_type::HEVC ||
|
||||
enc->codec == amf_codec_type::AV1)
|
||||
mb_size = 64; /* AMF HEVC & AV1 use 64x64 blocks */
|
||||
|
||||
const uint32_t mb_width = (enc->cx + mb_size - 1) / mb_size;
|
||||
const uint32_t mb_height = (enc->cy + mb_size - 1) / mb_size;
|
||||
|
||||
if (!enc->roi_map) {
|
||||
AMFContext1Ptr context1(enc->amf_context);
|
||||
AMF_RESULT res = context1->AllocSurfaceEx(
|
||||
AMF_MEMORY_HOST, AMF_SURFACE_GRAY32, mb_width,
|
||||
mb_height,
|
||||
AMF_SURFACE_USAGE_DEFAULT | AMF_SURFACE_USAGE_LINEAR,
|
||||
AMF_MEMORY_CPU_DEFAULT, &enc->roi_map);
|
||||
|
||||
if (res != AMF_OK) {
|
||||
warn("Failed allocating surface for ROI map!");
|
||||
/* Clear ROI to prevent failure the next frame */
|
||||
obs_encoder_clear_roi(enc->encoder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is just following the SimpleROI example. */
|
||||
amf_uint32 *pBuf =
|
||||
(amf_uint32 *)enc->roi_map->GetPlaneAt(0)->GetNative();
|
||||
amf_int32 pitch = enc->roi_map->GetPlaneAt(0)->GetHPitch();
|
||||
memset(pBuf, 0, pitch * mb_height);
|
||||
|
||||
roi_params par{mb_width, mb_height, pitch,
|
||||
enc->codec == amf_codec_type::AVC, pBuf};
|
||||
obs_encoder_enum_roi(enc->encoder, roi_cb, &par);
|
||||
|
||||
enc->roi_increment = obs_encoder_get_roi_increment(enc->encoder);
|
||||
}
|
||||
|
||||
static void add_roi(amf_base *enc, AMFSurface *amf_surf)
|
||||
{
|
||||
const uint32_t increment = obs_encoder_get_roi_increment(enc->encoder);
|
||||
|
||||
if (increment != enc->roi_increment || !enc->roi_increment)
|
||||
create_roi(enc, amf_surf);
|
||||
|
||||
if (enc->codec == amf_codec_type::AVC)
|
||||
amf_surf->SetProperty(AMF_VIDEO_ENCODER_ROI_DATA, enc->roi_map);
|
||||
else if (enc->codec == amf_codec_type::HEVC)
|
||||
amf_surf->SetProperty(AMF_VIDEO_ENCODER_HEVC_ROI_DATA,
|
||||
enc->roi_map);
|
||||
else if (enc->codec == amf_codec_type::AV1)
|
||||
amf_surf->SetProperty(AMF_VIDEO_ENCODER_AV1_ROI_DATA,
|
||||
enc->roi_map);
|
||||
}
|
||||
|
||||
static void amf_encode_base(amf_base *enc, AMFSurface *amf_surf,
|
||||
encoder_packet *packet, bool *received_packet)
|
||||
{
|
||||
@ -591,6 +688,11 @@ static void amf_encode_base(amf_base *enc, AMFSurface *amf_surf,
|
||||
|
||||
bool waiting = true;
|
||||
while (waiting) {
|
||||
/* ----------------------------------- */
|
||||
/* add ROI data (if any) */
|
||||
if (enc->roi_supported && obs_encoder_has_roi(enc->encoder))
|
||||
add_roi(enc, amf_surf);
|
||||
|
||||
/* ----------------------------------- */
|
||||
/* submit frame */
|
||||
|
||||
@ -1377,6 +1479,8 @@ static void amf_avc_create_internal(amf_base *enc, obs_data_t *settings)
|
||||
&enc->max_throughput);
|
||||
caps->GetProperty(AMF_VIDEO_ENCODER_CAP_REQUESTED_THROUGHPUT,
|
||||
&enc->requested_throughput);
|
||||
caps->GetProperty(AMF_VIDEO_ENCODER_CAP_ROI,
|
||||
&enc->roi_supported);
|
||||
}
|
||||
|
||||
const char *preset = obs_data_get_string(settings, "preset");
|
||||
@ -1507,13 +1611,15 @@ static void register_avc()
|
||||
amf_encoder_info.get_properties = amf_avc_properties;
|
||||
amf_encoder_info.get_extra_data = amf_extra_data;
|
||||
amf_encoder_info.caps = OBS_ENCODER_CAP_PASS_TEXTURE |
|
||||
OBS_ENCODER_CAP_DYN_BITRATE;
|
||||
OBS_ENCODER_CAP_DYN_BITRATE |
|
||||
OBS_ENCODER_CAP_ROI;
|
||||
|
||||
obs_register_encoder(&amf_encoder_info);
|
||||
|
||||
amf_encoder_info.id = "h264_fallback_amf";
|
||||
amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL |
|
||||
OBS_ENCODER_CAP_DYN_BITRATE;
|
||||
OBS_ENCODER_CAP_DYN_BITRATE |
|
||||
OBS_ENCODER_CAP_ROI;
|
||||
amf_encoder_info.encode_texture = nullptr;
|
||||
amf_encoder_info.create = amf_avc_create_fallback;
|
||||
amf_encoder_info.encode = amf_encode_fallback;
|
||||
@ -1713,6 +1819,8 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings)
|
||||
caps->GetProperty(
|
||||
AMF_VIDEO_ENCODER_HEVC_CAP_REQUESTED_THROUGHPUT,
|
||||
&enc->requested_throughput);
|
||||
caps->GetProperty(AMF_VIDEO_ENCODER_HEVC_CAP_ROI,
|
||||
&enc->roi_supported);
|
||||
}
|
||||
|
||||
const bool is10bit = enc->amf_format == AMF_SURFACE_P010;
|
||||
@ -1861,13 +1969,15 @@ static void register_hevc()
|
||||
amf_encoder_info.get_properties = amf_hevc_properties;
|
||||
amf_encoder_info.get_extra_data = amf_extra_data;
|
||||
amf_encoder_info.caps = OBS_ENCODER_CAP_PASS_TEXTURE |
|
||||
OBS_ENCODER_CAP_DYN_BITRATE;
|
||||
OBS_ENCODER_CAP_DYN_BITRATE |
|
||||
OBS_ENCODER_CAP_ROI;
|
||||
|
||||
obs_register_encoder(&amf_encoder_info);
|
||||
|
||||
amf_encoder_info.id = "h265_fallback_amf";
|
||||
amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL |
|
||||
OBS_ENCODER_CAP_DYN_BITRATE;
|
||||
OBS_ENCODER_CAP_DYN_BITRATE |
|
||||
OBS_ENCODER_CAP_ROI;
|
||||
amf_encoder_info.encode_texture = nullptr;
|
||||
amf_encoder_info.create = amf_hevc_create_fallback;
|
||||
amf_encoder_info.encode = amf_encode_fallback;
|
||||
@ -2055,6 +2165,8 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings)
|
||||
caps->GetProperty(
|
||||
AMF_VIDEO_ENCODER_AV1_CAP_REQUESTED_THROUGHPUT,
|
||||
&enc->requested_throughput);
|
||||
/* For some reason there's no specific CAP for AV1, but should always be supported */
|
||||
enc->roi_supported = true;
|
||||
}
|
||||
|
||||
const bool is10bit = enc->amf_format == AMF_SURFACE_P010;
|
||||
@ -2187,13 +2299,15 @@ static void register_av1()
|
||||
amf_encoder_info.get_properties = amf_av1_properties;
|
||||
amf_encoder_info.get_extra_data = amf_extra_data;
|
||||
amf_encoder_info.caps = OBS_ENCODER_CAP_PASS_TEXTURE |
|
||||
OBS_ENCODER_CAP_DYN_BITRATE;
|
||||
OBS_ENCODER_CAP_DYN_BITRATE |
|
||||
OBS_ENCODER_CAP_ROI;
|
||||
|
||||
obs_register_encoder(&amf_encoder_info);
|
||||
|
||||
amf_encoder_info.id = "av1_fallback_amf";
|
||||
amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL |
|
||||
OBS_ENCODER_CAP_DYN_BITRATE;
|
||||
OBS_ENCODER_CAP_DYN_BITRATE |
|
||||
OBS_ENCODER_CAP_ROI;
|
||||
amf_encoder_info.encode_texture = nullptr;
|
||||
amf_encoder_info.create = amf_av1_create_fallback;
|
||||
amf_encoder_info.encode = amf_encode_fallback;
|
||||
|
Loading…
Reference in New Issue
Block a user