0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 13:08:50 +02:00

libobs/media-io: Add frame funcs for separate GPU thread

Normally, the total and skipped frame count for the encoder is performed
in the video-io thread.  However, because a new thread is being
introduced for texture-based encoding, the frontend has no way of being
able to query that.  So, instead of making the frontend query that data
separately, just make the texture encoder thread increment the values of
video-io.  That way, the frontend doesn't need to change any code, and
can continue using the same functions for determining the total/skipped
frame count.

This can cause the frame count to be doubled if both a texture-based
encoder and a raw data encoder is active at the same time, but it's an
acceptable alternative.
This commit is contained in:
jp9000 2019-02-05 17:16:40 -08:00
parent 0be02564cb
commit 36ffa65b68
2 changed files with 86 additions and 27 deletions

View File

@ -65,8 +65,8 @@ struct video_output {
os_sem_t *update_semaphore;
uint64_t frame_time;
uint32_t skipped_frames;
uint32_t total_frames;
volatile long skipped_frames;
volatile long total_frames;
bool initialized;
@ -77,6 +77,9 @@ struct video_output {
size_t first_added;
size_t last_added;
struct cached_frame_info cache[MAX_CACHE_SIZE];
volatile bool raw_active;
volatile long gpu_refs;
};
/* ------------------------------------------------------------------------- */
@ -156,7 +159,7 @@ static inline bool video_output_cur_frame(struct video_output *video)
video->last_added = video->first_added;
} else if (skipped) {
--frame_info->skipped;
++video->skipped_frames;
os_atomic_inc_long(&video->skipped_frames);
}
pthread_mutex_unlock(&video->data_mutex);
@ -182,10 +185,10 @@ static void *video_thread(void *param)
profile_start(video_thread_name);
while (!video->stop && !video_output_cur_frame(video)) {
video->total_frames++;
os_atomic_inc_long(&video->total_frames);
}
video->total_frames++;
os_atomic_inc_long(&video->total_frames);
profile_end(video_thread_name);
profile_reenable_thread();
@ -330,6 +333,12 @@ static inline bool video_input_init(struct video_input *input,
return true;
}
static inline void reset_frames(video_t *video)
{
os_atomic_set_long(&video->skipped_frames, 0);
os_atomic_set_long(&video->total_frames, 0);
}
bool video_output_connect(video_t *video,
const struct video_scale_info *conversion,
void (*callback)(void *param, struct video_data *frame),
@ -342,11 +351,6 @@ bool video_output_connect(video_t *video,
pthread_mutex_lock(&video->input_mutex);
if (video->inputs.num == 0) {
video->skipped_frames = 0;
video->total_frames = 0;
}
if (video_get_input_idx(video, callback, param) == DARRAY_INVALID) {
struct video_input input;
memset(&input, 0, sizeof(input));
@ -368,8 +372,15 @@ bool video_output_connect(video_t *video,
input.conversion.height = video->info.height;
success = video_input_init(&input, video);
if (success)
if (success) {
if (video->inputs.num == 0) {
if (!os_atomic_load_long(&video->gpu_refs)) {
reset_frames(video);
}
os_atomic_set_bool(&video->raw_active, true);
}
da_push_back(video->inputs, &input);
}
}
pthread_mutex_unlock(&video->input_mutex);
@ -377,6 +388,24 @@ bool video_output_connect(video_t *video,
return success;
}
static void log_skipped(video_t *video)
{
long skipped = os_atomic_load_long(&video->skipped_frames);
double percentage_skipped =
(double)skipped /
(double)os_atomic_load_long(&video->total_frames) *
100.0;
if (skipped)
blog(LOG_INFO, "Video stopped, number of "
"skipped frames due "
"to encoding lag: "
"%"PRIu32"/%"PRIu32" (%0.1f%%)",
video->skipped_frames,
video->total_frames,
percentage_skipped);
}
void video_output_disconnect(video_t *video,
void (*callback)(void *param, struct video_data *frame),
void *param)
@ -390,20 +419,13 @@ void video_output_disconnect(video_t *video,
if (idx != DARRAY_INVALID) {
video_input_free(video->inputs.array+idx);
da_erase(video->inputs, idx);
}
if (video->inputs.num == 0) {
double percentage_skipped = (double)video->skipped_frames /
(double)video->total_frames * 100.0;
if (video->skipped_frames)
blog(LOG_INFO, "Video stopped, number of "
"skipped frames due "
"to encoding lag: "
"%"PRIu32"/%"PRIu32" (%0.1f%%)",
video->skipped_frames,
video->total_frames,
percentage_skipped);
if (video->inputs.num == 0) {
os_atomic_set_bool(&video->raw_active, false);
if (!os_atomic_load_long(&video->gpu_refs)) {
log_skipped(video);
}
}
}
pthread_mutex_unlock(&video->input_mutex);
@ -412,7 +434,7 @@ void video_output_disconnect(video_t *video,
bool video_output_active(const video_t *video)
{
if (!video) return false;
return video->inputs.num != 0;
return os_atomic_load_bool(&video->raw_active);
}
const struct video_output_info *video_output_get_info(const video_t *video)
@ -521,10 +543,42 @@ double video_output_get_frame_rate(const video_t *video)
uint32_t video_output_get_skipped_frames(const video_t *video)
{
return video->skipped_frames;
return (uint32_t)os_atomic_load_long(&video->skipped_frames);
}
uint32_t video_output_get_total_frames(const video_t *video)
{
return video->total_frames;
return (uint32_t)os_atomic_load_long(&video->total_frames);
}
/* Note: These four functions below are a very slight bit of a hack. If the
* texture encoder thread is active while the raw encoder thread is active, the
* total frame count will just be doubled while they're both active. Which is
* fine. What's more important is having a relatively accurate skipped frame
* count. */
void video_output_inc_texture_encoders(video_t *video)
{
if (os_atomic_inc_long(&video->gpu_refs) == 1 &&
!os_atomic_load_bool(&video->raw_active)) {
reset_frames(video);
}
}
void video_output_dec_texture_encoders(video_t *video)
{
if (os_atomic_dec_long(&video->gpu_refs) == 0 &&
!os_atomic_load_bool(&video->raw_active)) {
log_skipped(video);
}
}
void video_output_inc_texture_frames(video_t *video)
{
os_atomic_inc_long(&video->total_frames);
}
void video_output_inc_texture_skipped_frames(video_t *video)
{
os_atomic_inc_long(&video->skipped_frames);
}

View File

@ -202,6 +202,11 @@ EXPORT double video_output_get_frame_rate(const video_t *video);
EXPORT uint32_t video_output_get_skipped_frames(const video_t *video);
EXPORT uint32_t video_output_get_total_frames(const video_t *video);
extern void video_output_inc_texture_encoders(video_t *video);
extern void video_output_dec_texture_encoders(video_t *video);
extern void video_output_inc_texture_frames(video_t *video);
extern void video_output_inc_texture_skipped_frames(video_t *video);
#ifdef __cplusplus
}