Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4654cb7126 |
@ -1,60 +1,141 @@
|
|||||||
#include "fps_counter.h"
|
#include "fps_counter.h"
|
||||||
|
|
||||||
#include <SDL2/SDL_timer.h>
|
#include <SDL2/SDL_timer.h>
|
||||||
|
#include <SDL2/SDL_assert.h>
|
||||||
|
|
||||||
|
#include "lock_util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
void
|
#define FPS_COUNTER_INTERVAL 1000
|
||||||
fps_counter_init(struct fps_counter *counter) {
|
|
||||||
counter->started = false;
|
|
||||||
// no need to initialize the other fields, they are meaningful only when
|
|
||||||
// started is true
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
bool
|
||||||
fps_counter_start(struct fps_counter *counter) {
|
fps_counter_init(struct fps_counter *counter) {
|
||||||
counter->started = true;
|
counter->mutex = SDL_CreateMutex();
|
||||||
counter->slice_start = SDL_GetTicks();
|
if (!counter->mutex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter->state_cond = SDL_CreateCond();
|
||||||
|
if (!counter->state_cond) {
|
||||||
|
SDL_DestroyMutex(counter->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter->thread = NULL;
|
||||||
|
counter->started = false;
|
||||||
|
counter->interrupted = false;
|
||||||
counter->nr_rendered = 0;
|
counter->nr_rendered = 0;
|
||||||
counter->nr_skipped = 0;
|
counter->nr_skipped = 0;
|
||||||
|
// no need to initialize slice_start, it is meaningful only when started
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_stop(struct fps_counter *counter) {
|
fps_counter_destroy(struct fps_counter *counter) {
|
||||||
counter->started = false;
|
SDL_DestroyCond(counter->state_cond);
|
||||||
|
SDL_DestroyMutex(counter->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
display_fps(struct fps_counter *counter) {
|
display_fps(struct fps_counter *counter) {
|
||||||
|
unsigned rendered_per_second =
|
||||||
|
counter->nr_rendered * 1000 / FPS_COUNTER_INTERVAL;
|
||||||
if (counter->nr_skipped) {
|
if (counter->nr_skipped) {
|
||||||
LOGI("%d fps (+%d frames skipped)", counter->nr_rendered,
|
unsigned skipped_per_second =
|
||||||
counter->nr_skipped);
|
counter->nr_skipped * 1000 / FPS_COUNTER_INTERVAL;
|
||||||
|
LOGI("%u fps (+%u frames skipped)", rendered_per_second,
|
||||||
|
skipped_per_second);
|
||||||
} else {
|
} else {
|
||||||
LOGI("%d fps", counter->nr_rendered);
|
LOGI("%u fps", rendered_per_second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
check_expired(struct fps_counter *counter) {
|
run_fps_counter(void *data) {
|
||||||
uint32_t now = SDL_GetTicks();
|
struct fps_counter *counter = data;
|
||||||
if (now - counter->slice_start >= 1000) {
|
|
||||||
display_fps(counter);
|
mutex_lock(counter->mutex);
|
||||||
// add a multiple of one second
|
while (!counter->interrupted) {
|
||||||
uint32_t elapsed_slices = (now - counter->slice_start) / 1000;
|
while (!counter->interrupted && !counter->started) {
|
||||||
counter->slice_start += 1000 * elapsed_slices;
|
cond_wait(counter->state_cond, counter->mutex);
|
||||||
counter->nr_rendered = 0;
|
}
|
||||||
counter->nr_skipped = 0;
|
while (!counter->interrupted && counter->started) {
|
||||||
|
uint32_t now = SDL_GetTicks();
|
||||||
|
if (now >= counter->next_timestamp) {
|
||||||
|
display_fps(counter);
|
||||||
|
counter->nr_rendered = 0;
|
||||||
|
counter->nr_skipped = 0;
|
||||||
|
// add a multiple of the interval
|
||||||
|
uint32_t elapsed_slices =
|
||||||
|
(now - counter->next_timestamp) / FPS_COUNTER_INTERVAL + 1;
|
||||||
|
counter->next_timestamp += FPS_COUNTER_INTERVAL * elapsed_slices;
|
||||||
|
}
|
||||||
|
SDL_assert(counter->next_timestamp > now);
|
||||||
|
uint32_t remaining = counter->next_timestamp - now;
|
||||||
|
|
||||||
|
// ignore the reason (timeout or signaled), we just loop anyway
|
||||||
|
cond_wait_timeout(counter->state_cond, counter->mutex, remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(counter->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
fps_counter_start(struct fps_counter *counter) {
|
||||||
|
if (!counter->thread) {
|
||||||
|
counter->thread =
|
||||||
|
SDL_CreateThread(run_fps_counter, "fps counter", counter);
|
||||||
|
if (!counter->thread) {
|
||||||
|
LOGE("Could not start FPS counter thread");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(counter->mutex);
|
||||||
|
counter->started = true;
|
||||||
|
counter->next_timestamp = SDL_GetTicks() + FPS_COUNTER_INTERVAL;
|
||||||
|
counter->nr_rendered = 0;
|
||||||
|
counter->nr_skipped = 0;
|
||||||
|
mutex_unlock(counter->mutex);
|
||||||
|
|
||||||
|
cond_signal(counter->state_cond);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fps_counter_stop(struct fps_counter *counter) {
|
||||||
|
mutex_lock(counter->mutex);
|
||||||
|
counter->started = false;
|
||||||
|
mutex_unlock(counter->mutex);
|
||||||
|
cond_signal(counter->state_cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fps_counter_interrupt(struct fps_counter *counter) {
|
||||||
|
if (counter->thread) {
|
||||||
|
mutex_lock(counter->mutex);
|
||||||
|
counter->interrupted = true;
|
||||||
|
mutex_unlock(counter->mutex);
|
||||||
|
// wake up blocking wait
|
||||||
|
cond_signal(counter->state_cond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fps_counter_join(struct fps_counter *counter) {
|
||||||
|
if (counter->thread) {
|
||||||
|
SDL_WaitThread(counter->thread, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
||||||
check_expired(counter);
|
|
||||||
++counter->nr_rendered;
|
++counter->nr_rendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_add_skipped_frame(struct fps_counter *counter) {
|
fps_counter_add_skipped_frame(struct fps_counter *counter) {
|
||||||
check_expired(counter);
|
|
||||||
++counter->nr_skipped;
|
++counter->nr_skipped;
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,41 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <SDL2/SDL_atomic.h>
|
||||||
|
#include <SDL2/SDL_mutex.h>
|
||||||
|
#include <SDL2/SDL_thread.h>
|
||||||
|
|
||||||
struct fps_counter {
|
struct fps_counter {
|
||||||
|
SDL_Thread *thread;
|
||||||
|
SDL_mutex *mutex;
|
||||||
|
SDL_cond *state_cond;
|
||||||
bool started;
|
bool started;
|
||||||
uint32_t slice_start; // initialized by SDL_GetTicks()
|
bool interrupted;
|
||||||
int nr_rendered;
|
unsigned nr_rendered;
|
||||||
int nr_skipped;
|
unsigned nr_skipped;
|
||||||
|
uint32_t next_timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
bool
|
||||||
fps_counter_init(struct fps_counter *counter);
|
fps_counter_init(struct fps_counter *counter);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
fps_counter_destroy(struct fps_counter *counter);
|
||||||
|
|
||||||
|
bool
|
||||||
fps_counter_start(struct fps_counter *counter);
|
fps_counter_start(struct fps_counter *counter);
|
||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_stop(struct fps_counter *counter);
|
fps_counter_stop(struct fps_counter *counter);
|
||||||
|
|
||||||
|
// request to stop the thread (on quit)
|
||||||
|
// must be called before fps_counter_join()
|
||||||
|
void
|
||||||
|
fps_counter_interrupt(struct fps_counter *counter);
|
||||||
|
|
||||||
|
void
|
||||||
|
fps_counter_join(struct fps_counter *counter);
|
||||||
|
|
||||||
void
|
void
|
||||||
fps_counter_add_rendered_frame(struct fps_counter *counter);
|
fps_counter_add_rendered_frame(struct fps_counter *counter);
|
||||||
|
|
||||||
|
@ -172,16 +172,19 @@ set_screen_power_mode(struct controller *controller,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
switch_fps_counter_state(struct video_buffer *vb) {
|
switch_fps_counter_state(struct fps_counter *fps_counter) {
|
||||||
mutex_lock(vb->mutex);
|
mutex_lock(fps_counter->mutex);
|
||||||
if (vb->fps_counter.started) {
|
if (fps_counter->started) {
|
||||||
|
fps_counter_stop(fps_counter);
|
||||||
LOGI("FPS counter stopped");
|
LOGI("FPS counter stopped");
|
||||||
fps_counter_stop(&vb->fps_counter);
|
|
||||||
} else {
|
} else {
|
||||||
LOGI("FPS counter started");
|
if (fps_counter_start(fps_counter)) {
|
||||||
fps_counter_start(&vb->fps_counter);
|
LOGI("FPS counter started");
|
||||||
|
} else {
|
||||||
|
LOGE("FPS counter starting failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(vb->mutex);
|
mutex_unlock(fps_counter->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -339,7 +342,9 @@ input_manager_process_key(struct input_manager *input_manager,
|
|||||||
return;
|
return;
|
||||||
case SDLK_i:
|
case SDLK_i:
|
||||||
if (ctrl && !meta && !shift && !repeat && down) {
|
if (ctrl && !meta && !shift && !repeat && down) {
|
||||||
switch_fps_counter_state(input_manager->video_buffer);
|
struct fps_counter *fps_counter =
|
||||||
|
input_manager->video_buffer->fps_counter;
|
||||||
|
switch_fps_counter_state(fps_counter);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_n:
|
case SDLK_n:
|
||||||
|
@ -28,6 +28,16 @@ cond_wait(SDL_cond *cond, SDL_mutex *mutex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cond_wait_timeout(SDL_cond *cond, SDL_mutex *mutex, uint32_t ms) {
|
||||||
|
int r = SDL_CondWaitTimeout(cond, mutex, ms);
|
||||||
|
if (r < 0) {
|
||||||
|
LOGC("Could not wait on condition with timeout");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cond_signal(SDL_cond *cond) {
|
cond_signal(SDL_cond *cond) {
|
||||||
if (SDL_CondSignal(cond)) {
|
if (SDL_CondSignal(cond)) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef LOCKUTIL_H
|
#ifndef LOCKUTIL_H
|
||||||
#define LOCKUTIL_H
|
#define LOCKUTIL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// forward declarations
|
// forward declarations
|
||||||
typedef struct SDL_mutex SDL_mutex;
|
typedef struct SDL_mutex SDL_mutex;
|
||||||
typedef struct SDL_cond SDL_cond;
|
typedef struct SDL_cond SDL_cond;
|
||||||
@ -14,6 +16,10 @@ mutex_unlock(SDL_mutex *mutex);
|
|||||||
void
|
void
|
||||||
cond_wait(SDL_cond *cond, SDL_mutex *mutex);
|
cond_wait(SDL_cond *cond, SDL_mutex *mutex);
|
||||||
|
|
||||||
|
// return 0 or SDL_MUTEX_TIMEDOUT
|
||||||
|
int
|
||||||
|
cond_wait_timeout(SDL_cond *cond, SDL_mutex *mutex, uint32_t ms);
|
||||||
|
|
||||||
void
|
void
|
||||||
cond_signal(SDL_cond *cond);
|
cond_signal(SDL_cond *cond);
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
static struct server server = SERVER_INITIALIZER;
|
static struct server server = SERVER_INITIALIZER;
|
||||||
static struct screen screen = SCREEN_INITIALIZER;
|
static struct screen screen = SCREEN_INITIALIZER;
|
||||||
|
static struct fps_counter fps_counter;
|
||||||
static struct video_buffer video_buffer;
|
static struct video_buffer video_buffer;
|
||||||
static struct stream stream;
|
static struct stream stream;
|
||||||
static struct decoder decoder;
|
static struct decoder decoder;
|
||||||
@ -293,6 +294,7 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
|
bool fps_counter_initialized = false;
|
||||||
bool video_buffer_initialized = false;
|
bool video_buffer_initialized = false;
|
||||||
bool file_handler_initialized = false;
|
bool file_handler_initialized = false;
|
||||||
bool recorder_initialized = false;
|
bool recorder_initialized = false;
|
||||||
@ -320,7 +322,13 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
|
|
||||||
struct decoder *dec = NULL;
|
struct decoder *dec = NULL;
|
||||||
if (options->display) {
|
if (options->display) {
|
||||||
if (!video_buffer_init(&video_buffer, options->render_expired_frames)) {
|
if (!fps_counter_init(&fps_counter)) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
fps_counter_initialized = true;
|
||||||
|
|
||||||
|
if (!video_buffer_init(&video_buffer, &fps_counter,
|
||||||
|
options->render_expired_frames)) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
video_buffer_initialized = true;
|
video_buffer_initialized = true;
|
||||||
@ -414,6 +422,9 @@ end:
|
|||||||
if (file_handler_initialized) {
|
if (file_handler_initialized) {
|
||||||
file_handler_stop(&file_handler);
|
file_handler_stop(&file_handler);
|
||||||
}
|
}
|
||||||
|
if (fps_counter_initialized) {
|
||||||
|
fps_counter_interrupt(&fps_counter);
|
||||||
|
}
|
||||||
|
|
||||||
// shutdown the sockets and kill the server
|
// shutdown the sockets and kill the server
|
||||||
server_stop(&server);
|
server_stop(&server);
|
||||||
@ -443,6 +454,11 @@ end:
|
|||||||
video_buffer_destroy(&video_buffer);
|
video_buffer_destroy(&video_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fps_counter_initialized) {
|
||||||
|
fps_counter_join(&fps_counter);
|
||||||
|
fps_counter_destroy(&fps_counter);
|
||||||
|
}
|
||||||
|
|
||||||
if (options->show_touches) {
|
if (options->show_touches) {
|
||||||
if (!show_touches_waited) {
|
if (!show_touches_waited) {
|
||||||
// wait the process which enabled "show touches"
|
// wait the process which enabled "show touches"
|
||||||
|
@ -10,7 +10,10 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
video_buffer_init(struct video_buffer *vb, bool render_expired_frames) {
|
video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter,
|
||||||
|
bool render_expired_frames) {
|
||||||
|
vb->fps_counter = fps_counter;
|
||||||
|
|
||||||
if (!(vb->decoding_frame = av_frame_alloc())) {
|
if (!(vb->decoding_frame = av_frame_alloc())) {
|
||||||
goto error_0;
|
goto error_0;
|
||||||
}
|
}
|
||||||
@ -37,7 +40,6 @@ video_buffer_init(struct video_buffer *vb, bool render_expired_frames) {
|
|||||||
// there is initially no rendering frame, so consider it has already been
|
// there is initially no rendering frame, so consider it has already been
|
||||||
// consumed
|
// consumed
|
||||||
vb->rendering_frame_consumed = true;
|
vb->rendering_frame_consumed = true;
|
||||||
fps_counter_init(&vb->fps_counter);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -76,8 +78,8 @@ video_buffer_offer_decoded_frame(struct video_buffer *vb,
|
|||||||
cond_wait(vb->rendering_frame_consumed_cond, vb->mutex);
|
cond_wait(vb->rendering_frame_consumed_cond, vb->mutex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vb->fps_counter.started && !vb->rendering_frame_consumed) {
|
if (vb->fps_counter->started && !vb->rendering_frame_consumed) {
|
||||||
fps_counter_add_skipped_frame(&vb->fps_counter);
|
fps_counter_add_skipped_frame(vb->fps_counter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +95,8 @@ const AVFrame *
|
|||||||
video_buffer_consume_rendered_frame(struct video_buffer *vb) {
|
video_buffer_consume_rendered_frame(struct video_buffer *vb) {
|
||||||
SDL_assert(!vb->rendering_frame_consumed);
|
SDL_assert(!vb->rendering_frame_consumed);
|
||||||
vb->rendering_frame_consumed = true;
|
vb->rendering_frame_consumed = true;
|
||||||
if (vb->fps_counter.started) {
|
if (vb->fps_counter->started) {
|
||||||
fps_counter_add_rendered_frame(&vb->fps_counter);
|
fps_counter_add_rendered_frame(vb->fps_counter);
|
||||||
}
|
}
|
||||||
if (vb->render_expired_frames) {
|
if (vb->render_expired_frames) {
|
||||||
// unblock video_buffer_offer_decoded_frame()
|
// unblock video_buffer_offer_decoded_frame()
|
||||||
|
@ -17,11 +17,12 @@ struct video_buffer {
|
|||||||
bool interrupted;
|
bool interrupted;
|
||||||
SDL_cond *rendering_frame_consumed_cond;
|
SDL_cond *rendering_frame_consumed_cond;
|
||||||
bool rendering_frame_consumed;
|
bool rendering_frame_consumed;
|
||||||
struct fps_counter fps_counter;
|
struct fps_counter *fps_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
video_buffer_init(struct video_buffer *vb, bool render_expired_frames);
|
video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter,
|
||||||
|
bool render_expired_frames);
|
||||||
|
|
||||||
void
|
void
|
||||||
video_buffer_destroy(struct video_buffer *vb);
|
video_buffer_destroy(struct video_buffer *vb);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user