diff --git a/app/meson.build b/app/meson.build index d230702e..18838f8b 100644 --- a/app/meson.build +++ b/app/meson.build @@ -15,6 +15,7 @@ src = [ 'src/opengl.c', 'src/receiver.c', 'src/recorder.c', + 'src/resizer.c', 'src/scrcpy.c', 'src/screen.c', 'src/server.c', diff --git a/app/src/resizer.c b/app/src/resizer.c new file mode 100644 index 00000000..4bb6ab85 --- /dev/null +++ b/app/src/resizer.c @@ -0,0 +1,132 @@ +#include "resizer.h" + +#include + +#include "util/log.h" + +bool +sc_resizer_init(struct sc_resizer *resizer, struct video_buffer *vb_in, + struct video_buffer *vb_out, struct size size) { + bool ok = sc_mutex_init(&resizer->mutex); + if (!ok) { + return false; + } + + ok = sc_cond_init(&resizer->req_cond); + if (!ok) { + sc_mutex_destroy(&resizer->mutex); + return false; + } + + resizer->resized_frame = av_frame_alloc(); + if (!resizer->resized_frame) { + sc_cond_destroy(&resizer->req_cond); + sc_mutex_destroy(&resizer->mutex); + return false; + } + + resizer->vb_in = vb_in; + resizer->vb_out = vb_out; + resizer->size = size; + + resizer->input_frame = NULL; + resizer->has_request = false; + resizer->has_new_frame = false; + resizer->interrupted = false; + + return true; +} + +void +sc_resizer_destroy(struct sc_resizer *resizer) { + av_frame_free(&resizer->resized_frame); + sc_cond_destroy(&resizer->req_cond); + sc_mutex_destroy(&resizer->mutex); +} + +static bool +sc_resizer_swscale(struct sc_resizer *resizer) { + assert(!resizer->resized_frame->buf[0]); // The frame must be "empty" + + return false; +} + +static int +run_resizer(void *data) { + struct sc_resizer *resizer = data; + + sc_mutex_lock(&resizer->mutex); + while (!resizer->interrupted) { + while (!resizer->interrupted && !resizer->has_request) { + sc_cond_wait(&resizer->req_cond, &resizer->mutex); + } + + if (resizer->has_new_frame) { + resizer->input_frame = + video_buffer_consumer_take_frame(resizer->vb_in); + + resizer->has_new_frame = false; + } + + resizer->has_request = false; + sc_mutex_unlock(&resizer->mutex); + + // Do the actual work without mutex + sc_resizer_swscale(resizer); + + video_buffer_producer_offer_frame(resizer->vb_out, + &resizer->resized_frame); + + sc_mutex_lock(&resizer->mutex); + } + sc_mutex_unlock(&resizer->mutex); + + return 0; +} + +bool +sc_resizer_start(struct sc_resizer *resizer) { + LOGD("Starting resizer thread"); + + bool ok = sc_thread_create(&resizer->thread, run_resizer, "resizer", + resizer); + if (!ok) { + LOGE("Could not start resizer thread"); + return false; + } + + return true; +} + +void +sc_resizer_stop(struct sc_resizer *resizer) { + sc_mutex_lock(&resizer->mutex); + resizer->interrupted = true; + sc_cond_signal(&resizer->req_cond); + sc_mutex_unlock(&resizer->mutex); + + video_buffer_interrupt(resizer->vb_out); +} + +void +sc_resizer_join(struct sc_resizer *resizer) { + sc_thread_join(&resizer->thread, NULL); +} + +void +sc_resizer_process_new_frame(struct sc_resizer *resizer) { + sc_mutex_lock(&resizer->mutex); + resizer->has_request = true; + resizer->has_new_frame = true; + sc_cond_signal(&resizer->req_cond); + sc_mutex_unlock(&resizer->mutex); +} + +void +sc_resizer_process_new_size(struct sc_resizer *resizer, struct size size) { + sc_mutex_lock(&resizer->mutex); + resizer->size = size; + resizer->has_request = true; + sc_cond_signal(&resizer->req_cond); + sc_mutex_unlock(&resizer->mutex); +} diff --git a/app/src/resizer.h b/app/src/resizer.h new file mode 100644 index 00000000..eb1d929c --- /dev/null +++ b/app/src/resizer.h @@ -0,0 +1,53 @@ +#ifndef SC_RESIZER +#define SC_RESIZER + +#include "common.h" + +#include +#include + +#include "coords.h" +#include "util/thread.h" +#include "video_buffer.h" + +struct sc_resizer { + struct video_buffer *vb_in; + struct video_buffer *vb_out; + struct size size; + + // valid until the next call to video_buffer_consumer_take_frame(vb_in) + const AVFrame *input_frame; + AVFrame *resized_frame; + + sc_thread thread; + sc_mutex mutex; + sc_cond req_cond; + + bool has_request; + bool has_new_frame; + bool interrupted; +}; + +bool +sc_resizer_init(struct sc_resizer *resizer, struct video_buffer *vb_in, + struct video_buffer *vb_out, struct size initial_size); + +void +sc_resizer_destroy(struct sc_resizer *resizer); + +bool +sc_resizer_start(struct sc_resizer *resizer); + +void +sc_resizer_stop(struct sc_resizer *resizer); + +void +sc_resizer_join(struct sc_resizer *resizer); + +void +sc_resizer_process_new_frame(struct sc_resizer *resizer); + +void +sc_resizer_process_new_size(struct sc_resizer *resizer, struct size size); + +#endif