mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-09-01 05:44:43 +08:00
libobs: Add encoder ROI functions
This commit is contained in:
@@ -52,6 +52,7 @@ static bool init_encoder(struct obs_encoder *encoder, const char *name,
|
||||
pthread_mutex_init_value(&encoder->callbacks_mutex);
|
||||
pthread_mutex_init_value(&encoder->outputs_mutex);
|
||||
pthread_mutex_init_value(&encoder->pause.mutex);
|
||||
pthread_mutex_init_value(&encoder->roi_mutex);
|
||||
|
||||
if (!obs_context_data_init(&encoder->context, OBS_OBJ_TYPE_ENCODER,
|
||||
settings, name, NULL, hotkey_data, false))
|
||||
@@ -64,6 +65,8 @@ static bool init_encoder(struct obs_encoder *encoder, const char *name,
|
||||
return false;
|
||||
if (pthread_mutex_init(&encoder->pause.mutex, NULL) != 0)
|
||||
return false;
|
||||
if (pthread_mutex_init(&encoder->roi_mutex, NULL) != 0)
|
||||
return false;
|
||||
|
||||
if (encoder->orig_info.get_defaults) {
|
||||
encoder->orig_info.get_defaults(encoder->context.settings);
|
||||
@@ -377,10 +380,12 @@ static void obs_encoder_actually_destroy(obs_encoder_t *encoder)
|
||||
if (encoder->context.data)
|
||||
encoder->info.destroy(encoder->context.data);
|
||||
da_free(encoder->callbacks);
|
||||
da_free(encoder->roi);
|
||||
pthread_mutex_destroy(&encoder->init_mutex);
|
||||
pthread_mutex_destroy(&encoder->callbacks_mutex);
|
||||
pthread_mutex_destroy(&encoder->outputs_mutex);
|
||||
pthread_mutex_destroy(&encoder->pause.mutex);
|
||||
pthread_mutex_destroy(&encoder->roi_mutex);
|
||||
obs_context_data_free(&encoder->context);
|
||||
if (encoder->owns_info_id)
|
||||
bfree((void *)encoder->info.id);
|
||||
@@ -1874,3 +1879,90 @@ uint64_t obs_encoder_get_pause_offset(const obs_encoder_t *encoder)
|
||||
{
|
||||
return encoder ? encoder->pause.ts_offset : 0;
|
||||
}
|
||||
|
||||
bool obs_encoder_has_roi(const obs_encoder_t *encoder)
|
||||
{
|
||||
return encoder->roi.num > 0;
|
||||
}
|
||||
|
||||
bool obs_encoder_add_roi(obs_encoder_t *encoder,
|
||||
const struct obs_encoder_roi *roi)
|
||||
{
|
||||
if (!roi)
|
||||
return false;
|
||||
if (!(encoder->info.caps & OBS_ENCODER_CAP_ROI))
|
||||
return false;
|
||||
/* Area smaller than the smallest possible block (16x16) */
|
||||
if (roi->bottom - roi->top < 16 || roi->right - roi->left < 16)
|
||||
return false;
|
||||
/* Other invalid ROIs */
|
||||
if (roi->priority < -1.0f || roi->priority > 1.0f)
|
||||
return false;
|
||||
|
||||
pthread_mutex_lock(&encoder->roi_mutex);
|
||||
da_push_back(encoder->roi, roi);
|
||||
encoder->roi_increment++;
|
||||
pthread_mutex_unlock(&encoder->roi_mutex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void obs_encoder_clear_roi(obs_encoder_t *encoder)
|
||||
{
|
||||
if (!encoder->roi.num)
|
||||
return;
|
||||
pthread_mutex_lock(&encoder->roi_mutex);
|
||||
da_clear(encoder->roi);
|
||||
encoder->roi_increment++;
|
||||
pthread_mutex_unlock(&encoder->roi_mutex);
|
||||
}
|
||||
|
||||
void obs_encoder_enum_roi(obs_encoder_t *encoder,
|
||||
void (*enum_proc)(void *, struct obs_encoder_roi *),
|
||||
void *param)
|
||||
{
|
||||
float scale_x = 0;
|
||||
float scale_y = 0;
|
||||
|
||||
/* Scale ROI passed to callback to output size */
|
||||
if (encoder->scaled_height && encoder->scaled_width) {
|
||||
const uint32_t width = video_output_get_width(encoder->media);
|
||||
const uint32_t height = video_output_get_height(encoder->media);
|
||||
|
||||
if (!width || !height)
|
||||
return;
|
||||
|
||||
scale_x = (float)encoder->scaled_width / (float)width;
|
||||
scale_y = (float)encoder->scaled_height / (float)height;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&encoder->roi_mutex);
|
||||
|
||||
size_t idx = encoder->roi.num;
|
||||
while (idx) {
|
||||
struct obs_encoder_roi *roi = &encoder->roi.array[--idx];
|
||||
|
||||
if (scale_x > 0 && scale_y > 0) {
|
||||
struct obs_encoder_roi scaled_roi = {
|
||||
.top = (uint32_t)((float)roi->top * scale_y),
|
||||
.bottom = (uint32_t)((float)roi->bottom *
|
||||
scale_y),
|
||||
.left = (uint32_t)((float)roi->left * scale_x),
|
||||
.right =
|
||||
(uint32_t)((float)roi->right * scale_x),
|
||||
.priority = roi->priority,
|
||||
};
|
||||
|
||||
enum_proc(param, &scaled_roi);
|
||||
} else {
|
||||
enum_proc(param, roi);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&encoder->roi_mutex);
|
||||
}
|
||||
|
||||
uint32_t obs_encoder_get_roi_increment(const obs_encoder_t *encoder)
|
||||
{
|
||||
return encoder->roi_increment;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ extern "C" {
|
||||
#define OBS_ENCODER_CAP_PASS_TEXTURE (1 << 1)
|
||||
#define OBS_ENCODER_CAP_DYN_BITRATE (1 << 2)
|
||||
#define OBS_ENCODER_CAP_INTERNAL (1 << 3)
|
||||
#define OBS_ENCODER_CAP_ROI (1 << 4)
|
||||
|
||||
/** Specifies the encoder type */
|
||||
enum obs_encoder_type {
|
||||
@@ -102,6 +103,23 @@ struct encoder_frame {
|
||||
int64_t pts;
|
||||
};
|
||||
|
||||
/** Encoder region of interest */
|
||||
struct obs_encoder_roi {
|
||||
/* The rectangle edges of the region are specified as number of pixels
|
||||
* from the input video's top and left edges (i.e. row/column 0). */
|
||||
uint32_t top;
|
||||
uint32_t bottom;
|
||||
uint32_t left;
|
||||
uint32_t right;
|
||||
|
||||
/* Priority is specified as a float value between -1 and 1.
|
||||
* These are converted to encoder-specific values by the encoder.
|
||||
* Values above 0 tell the encoder to increase quality for that region,
|
||||
* values below tell it to worsen it.
|
||||
* Not all encoders support negative values and they may be ignored. */
|
||||
float priority;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encoder interface
|
||||
*
|
||||
|
||||
@@ -1263,6 +1263,11 @@ struct obs_encoder {
|
||||
uint32_t frame_rate_divisor_counter; // only used for GPU encoders
|
||||
video_t *fps_override;
|
||||
|
||||
/* Regions of interest to prioritize during encoding */
|
||||
pthread_mutex_t roi_mutex;
|
||||
DARRAY(struct obs_encoder_roi) roi;
|
||||
uint32_t roi_increment;
|
||||
|
||||
int64_t cur_pts;
|
||||
|
||||
struct circlebuf audio_input_buffer[MAX_AV_PLANES];
|
||||
|
||||
@@ -2457,6 +2457,27 @@ EXPORT void obs_encoder_set_gpu_scale_type(obs_encoder_t *encoder,
|
||||
EXPORT bool obs_encoder_set_frame_rate_divisor(obs_encoder_t *encoder,
|
||||
uint32_t divisor);
|
||||
|
||||
/**
|
||||
* Adds region of interest (ROI) for an encoder. This allows prioritizing
|
||||
* quality of regions of the frame.
|
||||
* If regions overlap, regions added earlier take precedence.
|
||||
*
|
||||
* Returns false if the encoder does not support ROI or region is invalid.
|
||||
*/
|
||||
EXPORT bool obs_encoder_add_roi(obs_encoder_t *encoder,
|
||||
const struct obs_encoder_roi *roi);
|
||||
/** For video encoders, returns true if any ROIs were set */
|
||||
EXPORT bool obs_encoder_has_roi(const obs_encoder_t *encoder);
|
||||
/** Clear all regions */
|
||||
EXPORT void obs_encoder_clear_roi(obs_encoder_t *encoder);
|
||||
/** Enumerate regions with callback (reverse order of addition) */
|
||||
EXPORT void obs_encoder_enum_roi(obs_encoder_t *encoder,
|
||||
void (*enum_proc)(void *,
|
||||
struct obs_encoder_roi *),
|
||||
void *param);
|
||||
/** Get ROI increment, encoders must rebuild their ROI map if it has changed */
|
||||
EXPORT uint32_t obs_encoder_get_roi_increment(const obs_encoder_t *encoder);
|
||||
|
||||
/** For video encoders, returns true if pre-encode scaling is enabled */
|
||||
EXPORT bool obs_encoder_scaling_enabled(const obs_encoder_t *encoder);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user