Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a55cea1004 | ||
|
|
fe43453f47 | ||
|
|
0bdb995f2e | ||
|
|
dce0867737 | ||
|
|
5c4c28c973 | ||
|
|
98628f25b5 | ||
|
|
e1dbe4f71c | ||
|
|
b1734ab737 | ||
|
|
44aa7f2c88 | ||
|
|
626094ad13 | ||
|
|
a566635c43 | ||
|
|
862948b132 | ||
|
|
c0c4ba7009 | ||
|
|
c53bd4d8b6 | ||
|
|
54f5c42d7b | ||
|
|
21d206f360 | ||
|
|
d2689fc168 | ||
|
|
f6320c7e31 | ||
|
|
30e619d37f | ||
|
|
c0dde0fade | ||
|
|
ace438e52a | ||
|
|
8e83f3e8af |
@@ -11,7 +11,6 @@ src = [
|
||||
'src/event_converter.c',
|
||||
'src/file_handler.c',
|
||||
'src/fps_counter.c',
|
||||
'src/frame_texture.c',
|
||||
'src/input_manager.c',
|
||||
'src/opengl.c',
|
||||
'src/receiver.c',
|
||||
@@ -47,7 +46,6 @@ if not get_option('crossbuild_windows')
|
||||
dependency('libavformat'),
|
||||
dependency('libavcodec'),
|
||||
dependency('libavutil'),
|
||||
dependency('libswscale'),
|
||||
dependency('sdl2'),
|
||||
]
|
||||
|
||||
@@ -101,9 +99,6 @@ foreach f : check_functions
|
||||
endif
|
||||
endforeach
|
||||
|
||||
# expose the build type
|
||||
conf.set('NDEBUG', get_option('buildtype') != 'debug')
|
||||
|
||||
# the version, updated on release
|
||||
conf.set_quoted('SCRCPY_VERSION', meson.project_version())
|
||||
|
||||
|
||||
@@ -643,7 +643,6 @@ guess_record_format(const char *filename) {
|
||||
|
||||
static bool
|
||||
parse_scale_filter(const char *optarg, enum sc_scale_filter *filter) {
|
||||
// TODO store in a map and loop over the entries instead
|
||||
if (!strcmp(optarg, "none")) {
|
||||
*filter = SC_SCALE_FILTER_NONE;
|
||||
return true;
|
||||
@@ -652,48 +651,8 @@ parse_scale_filter(const char *optarg, enum sc_scale_filter *filter) {
|
||||
*filter = SC_SCALE_FILTER_TRILINEAR;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "bilinear")) {
|
||||
*filter = SC_SCALE_FILTER_BILINEAR;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "bicubic")) {
|
||||
*filter = SC_SCALE_FILTER_BICUBIC;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "x")) {
|
||||
*filter = SC_SCALE_FILTER_X;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "point")) {
|
||||
*filter = SC_SCALE_FILTER_POINT;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "area")) {
|
||||
*filter = SC_SCALE_FILTER_AREA;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "bicublin")) {
|
||||
*filter = SC_SCALE_FILTER_BICUBLIN;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "gauss")) {
|
||||
*filter = SC_SCALE_FILTER_GAUSS;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "sinc")) {
|
||||
*filter = SC_SCALE_FILTER_SINC;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "lanczos")) {
|
||||
*filter = SC_SCALE_FILTER_LANCZOS;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(optarg, "spline")) {
|
||||
*filter = SC_SCALE_FILTER_SPLINE;
|
||||
return true;
|
||||
}
|
||||
LOGE("Unsupported scale filter: %s "
|
||||
"(expected one of [TODO])", optarg);
|
||||
"(expected \"none\" or \"trilinear\")", optarg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
# define SCRCPY_SDL_HAS_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRDUP
|
||||
#ifndef HAVE_STRDUP
|
||||
char *strdup(const char *s);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/time.h>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "events.h"
|
||||
@@ -18,18 +17,22 @@ push_frame(struct decoder *decoder) {
|
||||
video_buffer_offer_decoded_frame(decoder->video_buffer,
|
||||
&previous_frame_skipped);
|
||||
if (previous_frame_skipped) {
|
||||
// the previous EVENT_NEW_FRAME will consume this frame
|
||||
// the previous callback will consume this frame
|
||||
return;
|
||||
}
|
||||
static SDL_Event new_frame_event = {
|
||||
.type = EVENT_NEW_FRAME,
|
||||
};
|
||||
SDL_PushEvent(&new_frame_event);
|
||||
|
||||
decoder->cbs->on_new_frame(decoder, decoder->cbs_userdata);
|
||||
}
|
||||
|
||||
void
|
||||
decoder_init(struct decoder *decoder, struct video_buffer *vb) {
|
||||
decoder_init(struct decoder *decoder, struct video_buffer *vb,
|
||||
const struct decoder_callbacks *cbs, void *cbs_userdata) {
|
||||
decoder->video_buffer = vb;
|
||||
|
||||
assert(cbs);
|
||||
assert(cbs->on_new_frame);
|
||||
decoder->cbs = cbs;
|
||||
decoder->cbs_userdata = cbs_userdata;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -11,10 +11,20 @@ struct video_buffer;
|
||||
struct decoder {
|
||||
struct video_buffer *video_buffer;
|
||||
AVCodecContext *codec_ctx;
|
||||
|
||||
const struct decoder_callbacks *cbs;
|
||||
void *cbs_userdata;
|
||||
};
|
||||
|
||||
struct decoder_callbacks {
|
||||
// Called when a new frame can be consumed by
|
||||
// video_buffer_take_rendering_frame(decoder->video_buffer).
|
||||
void (*on_new_frame)(struct decoder *decoder, void *userdata);
|
||||
};
|
||||
|
||||
void
|
||||
decoder_init(struct decoder *decoder, struct video_buffer *vb);
|
||||
decoder_init(struct decoder *decoder, struct video_buffer *vb,
|
||||
const struct decoder_callbacks *cbs, void *cbs_userdata);
|
||||
|
||||
bool
|
||||
decoder_open(struct decoder *decoder, const AVCodec *codec);
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
#define EVENT_NEW_SESSION SDL_USEREVENT
|
||||
#define EVENT_NEW_FRAME (SDL_USEREVENT + 1)
|
||||
#define EVENT_STREAM_STOPPED (SDL_USEREVENT + 2)
|
||||
#define EVENT_NEW_FRAME SDL_USEREVENT
|
||||
#define EVENT_STREAM_STOPPED (SDL_USEREVENT + 1)
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
#include "frame_texture.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static inline bool
|
||||
is_swscale_enabled(enum sc_scale_filter scale_filter) {
|
||||
return scale_filter != SC_SCALE_FILTER_NONE
|
||||
&& scale_filter != SC_SCALE_FILTER_TRILINEAR;
|
||||
}
|
||||
|
||||
static SDL_Texture *
|
||||
create_texture(struct sc_frame_texture *ftex, struct size size) {
|
||||
SDL_Renderer *renderer = ftex->renderer;
|
||||
SDL_PixelFormatEnum fmt = is_swscale_enabled(ftex->scale_filter)
|
||||
? SDL_PIXELFORMAT_RGB24
|
||||
: SDL_PIXELFORMAT_YV12;
|
||||
SDL_Texture *texture = SDL_CreateTexture(renderer, fmt,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
size.width, size.height);
|
||||
if (!texture) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ftex->scale_filter == SC_SCALE_FILTER_TRILINEAR) {
|
||||
struct sc_opengl *gl = &ftex->gl;
|
||||
|
||||
SDL_GL_BindTexture(texture, NULL, NULL);
|
||||
|
||||
// Enable trilinear filtering for downscaling
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
gl->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -1.f);
|
||||
|
||||
SDL_GL_UnbindTexture(texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool
|
||||
sc_frame_texture_init(struct sc_frame_texture *ftex, SDL_Renderer *renderer,
|
||||
enum sc_scale_filter scale_filter,
|
||||
struct size initial_size) {
|
||||
SDL_RendererInfo renderer_info;
|
||||
int r = SDL_GetRendererInfo(renderer, &renderer_info);
|
||||
const char *renderer_name = r ? NULL : renderer_info.name;
|
||||
LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)");
|
||||
|
||||
ftex->scale_filter = scale_filter;
|
||||
|
||||
// starts with "opengl"
|
||||
bool use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
|
||||
if (use_opengl) {
|
||||
struct sc_opengl *gl = &ftex->gl;
|
||||
sc_opengl_init(gl);
|
||||
|
||||
LOGI("OpenGL version: %s", gl->version);
|
||||
|
||||
if (scale_filter == SC_SCALE_FILTER_TRILINEAR) {
|
||||
bool supports_mipmaps =
|
||||
sc_opengl_version_at_least(gl, 3, 0, /* OpenGL 3.0+ */
|
||||
2, 0 /* OpenGL ES 2.0+ */);
|
||||
if (!supports_mipmaps) {
|
||||
LOGW("Trilinear filtering disabled "
|
||||
"(OpenGL 3.0+ or ES 2.0+ required)");
|
||||
ftex->scale_filter = SC_SCALE_FILTER_NONE;
|
||||
}
|
||||
}
|
||||
} else if (scale_filter == SC_SCALE_FILTER_TRILINEAR) {
|
||||
LOGD("Trilinear filtering disabled (not an OpenGL renderer)");
|
||||
}
|
||||
|
||||
LOGD("Scale filter: %s\n", sc_scale_filter_name(ftex->scale_filter));
|
||||
|
||||
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, initial_size.width,
|
||||
initial_size.height);
|
||||
ftex->renderer = renderer;
|
||||
ftex->texture = create_texture(ftex, initial_size);
|
||||
if (!ftex->texture) {
|
||||
LOGC("Could not create texture: %s", SDL_GetError());
|
||||
SDL_DestroyRenderer(ftex->renderer);
|
||||
return false;
|
||||
}
|
||||
|
||||
ftex->texture_size = initial_size;
|
||||
ftex->decoded_frame = NULL;
|
||||
memset(ftex->data, 0, sizeof(ftex->data));
|
||||
memset(ftex->linesize, 0, sizeof(ftex->linesize));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
sc_frame_texture_destroy(struct sc_frame_texture *ftex) {
|
||||
if (ftex->texture) {
|
||||
SDL_DestroyTexture(ftex->texture);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
to_sws_filter(enum sc_scale_filter scale_filter) {
|
||||
switch (scale_filter) {
|
||||
case SC_SCALE_FILTER_BILINEAR: return SWS_BILINEAR;
|
||||
case SC_SCALE_FILTER_BICUBIC: return SWS_BICUBIC;
|
||||
case SC_SCALE_FILTER_X: return SWS_X;
|
||||
case SC_SCALE_FILTER_POINT: return SWS_POINT;
|
||||
case SC_SCALE_FILTER_AREA: return SWS_AREA;
|
||||
case SC_SCALE_FILTER_BICUBLIN: return SWS_BICUBLIN;
|
||||
case SC_SCALE_FILTER_GAUSS: return SWS_GAUSS;
|
||||
case SC_SCALE_FILTER_SINC: return SWS_SINC;
|
||||
case SC_SCALE_FILTER_LANCZOS: return SWS_LANCZOS;
|
||||
case SC_SCALE_FILTER_SPLINE: return SWS_SPLINE;
|
||||
default: assert(!"unsupported filter");
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
screen_generate_resized_frame(struct sc_frame_texture *ftex,
|
||||
struct size target_size) {
|
||||
assert(is_swscale_enabled(ftex->scale_filter));
|
||||
// TODO
|
||||
|
||||
if (ftex->data[0]) {
|
||||
av_freep(&ftex->data[0]);
|
||||
}
|
||||
|
||||
int ret = av_image_alloc(ftex->data, ftex->linesize, target_size.width,
|
||||
target_size.height, AV_PIX_FMT_RGB24, 16);
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const AVFrame *input = ftex->decoded_frame;
|
||||
assert(input);
|
||||
|
||||
int flags = to_sws_filter(ftex->scale_filter);
|
||||
struct SwsContext *ctx =
|
||||
sws_getContext(input->width, input->height, AV_PIX_FMT_YUV420P,
|
||||
target_size.width, target_size.height, AV_PIX_FMT_RGB24,
|
||||
flags, NULL, NULL, NULL);
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sws_scale(ctx, (const uint8_t *const *) input->data, input->linesize, 0,
|
||||
input->height, ftex->data, ftex->linesize);
|
||||
sws_freeContext(ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
sc_frame_texture_update_direct(struct sc_frame_texture *ftex,
|
||||
const AVFrame *frame) {
|
||||
struct size frame_size = {frame->width, frame->height};
|
||||
if (ftex->texture_size.width != frame_size.width
|
||||
|| ftex->texture_size.height != frame_size.height) {
|
||||
// Frame dimensions changed, destroy texture
|
||||
SDL_DestroyTexture(ftex->texture);
|
||||
|
||||
LOGI("New texture: %" PRIu16 "x%" PRIu16, frame_size.width,
|
||||
frame_size.height);
|
||||
ftex->texture = create_texture(ftex, frame_size);
|
||||
if (!ftex->texture) {
|
||||
LOGC("Could not create texture: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
ftex->texture_size = frame_size;
|
||||
}
|
||||
|
||||
SDL_UpdateYUVTexture(ftex->texture, NULL,
|
||||
frame->data[0], frame->linesize[0],
|
||||
frame->data[1], frame->linesize[1],
|
||||
frame->data[2], frame->linesize[2]);
|
||||
|
||||
if (ftex->scale_filter == SC_SCALE_FILTER_TRILINEAR) {
|
||||
SDL_GL_BindTexture(ftex->texture, NULL, NULL);
|
||||
ftex->gl.GenerateMipmap(GL_TEXTURE_2D);
|
||||
SDL_GL_UnbindTexture(ftex->texture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
sc_frame_texture_update_swscale(struct sc_frame_texture *ftex,
|
||||
const AVFrame *frame, struct size target_size) {
|
||||
if (ftex->texture_size.width != target_size.width
|
||||
|| ftex->texture_size.height != target_size.height) {
|
||||
// Frame dimensions changed, destroy texture
|
||||
SDL_DestroyTexture(ftex->texture);
|
||||
|
||||
ftex->texture = create_texture(ftex, target_size);
|
||||
if (!ftex->texture) {
|
||||
LOGC("Could not create texture: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
ftex->texture_size = target_size;
|
||||
}
|
||||
|
||||
// The frame is valid until the next call to
|
||||
// video_buffer_take_rendering_frame()
|
||||
ftex->decoded_frame = frame;
|
||||
|
||||
bool ok = screen_generate_resized_frame(ftex, target_size);
|
||||
if (!ok) {
|
||||
LOGE("Failed to resize frame\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(ftex->texture, NULL, ftex->data[0], ftex->linesize[0]);
|
||||
|
||||
if (ftex->scale_filter == SC_SCALE_FILTER_TRILINEAR) {
|
||||
SDL_GL_BindTexture(ftex->texture, NULL, NULL);
|
||||
ftex->gl.GenerateMipmap(GL_TEXTURE_2D);
|
||||
SDL_GL_UnbindTexture(ftex->texture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sc_frame_texture_update(struct sc_frame_texture *ftex, const AVFrame *frame,
|
||||
struct size target_size) {
|
||||
if (is_swscale_enabled(ftex->scale_filter)) {
|
||||
return sc_frame_texture_update_swscale(ftex, frame, target_size);
|
||||
}
|
||||
return sc_frame_texture_update_direct(ftex, frame);
|
||||
}
|
||||
|
||||
bool
|
||||
sc_frame_texture_resize(struct sc_frame_texture *ftex,
|
||||
struct size target_size) {
|
||||
if (is_swscale_enabled(ftex->scale_filter)) {
|
||||
return sc_frame_texture_update_swscale(ftex, ftex->decoded_frame,
|
||||
target_size);
|
||||
}
|
||||
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef SC_FRAME_TEXTURE_H
|
||||
#define SC_FRAME_TEXTURE_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include "coords.h"
|
||||
#include "opengl.h"
|
||||
#include "scrcpy.h"
|
||||
|
||||
struct sc_frame_texture {
|
||||
SDL_Renderer *renderer; // owned by struct screen
|
||||
|
||||
enum sc_scale_filter scale_filter;
|
||||
struct sc_opengl gl;
|
||||
|
||||
SDL_Texture *texture;
|
||||
struct size texture_size;
|
||||
|
||||
// For swscaling
|
||||
const AVFrame *decoded_frame; // owned by the video_buffer
|
||||
uint8_t *data[4];
|
||||
int linesize[4];
|
||||
};
|
||||
|
||||
bool
|
||||
sc_frame_texture_init(struct sc_frame_texture *ftex, SDL_Renderer *renderer,
|
||||
enum sc_scale_filter scale_filter,
|
||||
struct size initial_size);
|
||||
|
||||
void
|
||||
sc_frame_texture_destroy(struct sc_frame_texture *ftex);
|
||||
|
||||
bool
|
||||
sc_frame_texture_update(struct sc_frame_texture *ftex, const AVFrame *frame,
|
||||
struct size target_size);
|
||||
|
||||
bool
|
||||
sc_frame_texture_resize(struct sc_frame_texture *ftex, struct size target_size);
|
||||
|
||||
#endif
|
||||
@@ -286,7 +286,7 @@ rotate_client_right(struct screen *screen) {
|
||||
screen_set_rotation(screen, new_rotation);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
input_manager_process_text_input(struct input_manager *im,
|
||||
const SDL_TextInputEvent *event) {
|
||||
if (is_shortcut_mod(im, SDL_GetModState())) {
|
||||
@@ -366,7 +366,7 @@ convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
input_manager_process_key(struct input_manager *im,
|
||||
const SDL_KeyboardEvent *event) {
|
||||
// control: indicates the state of the command-line option --no-control
|
||||
@@ -551,7 +551,7 @@ convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
input_manager_process_mouse_motion(struct input_manager *im,
|
||||
const SDL_MouseMotionEvent *event) {
|
||||
if (!event->state) {
|
||||
@@ -605,7 +605,7 @@ convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
input_manager_process_touch(struct input_manager *im,
|
||||
const SDL_TouchFingerEvent *event) {
|
||||
struct control_msg msg;
|
||||
@@ -637,7 +637,7 @@ convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
input_manager_process_mouse_button(struct input_manager *im,
|
||||
const SDL_MouseButtonEvent *event) {
|
||||
bool control = im->control;
|
||||
@@ -736,7 +736,7 @@ convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
input_manager_process_mouse_wheel(struct input_manager *im,
|
||||
const SDL_MouseWheelEvent *event) {
|
||||
struct control_msg msg;
|
||||
@@ -746,3 +746,46 @@ input_manager_process_mouse_wheel(struct input_manager *im,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
input_manager_handle_event(struct input_manager *im, SDL_Event *event) {
|
||||
switch (event->type) {
|
||||
case SDL_TEXTINPUT:
|
||||
if (!im->control) {
|
||||
return true;
|
||||
}
|
||||
input_manager_process_text_input(im, &event->text);
|
||||
return true;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
// some key events do not interact with the device, so process the
|
||||
// event even if control is disabled
|
||||
input_manager_process_key(im, &event->key);
|
||||
return true;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (!im->control) {
|
||||
break;
|
||||
}
|
||||
input_manager_process_mouse_motion(im, &event->motion);
|
||||
return true;
|
||||
case SDL_MOUSEWHEEL:
|
||||
if (!im->control) {
|
||||
break;
|
||||
}
|
||||
input_manager_process_mouse_wheel(im, &event->wheel);
|
||||
return true;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
// some mouse events do not interact with the device, so process
|
||||
// the event even if control is disabled
|
||||
input_manager_process_mouse_button(im, &event->button);
|
||||
return true;
|
||||
case SDL_FINGERMOTION:
|
||||
case SDL_FINGERDOWN:
|
||||
case SDL_FINGERUP:
|
||||
input_manager_process_touch(im, &event->tfinger);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -40,28 +40,7 @@ void
|
||||
input_manager_init(struct input_manager *im,
|
||||
const struct scrcpy_options *options);
|
||||
|
||||
void
|
||||
input_manager_process_text_input(struct input_manager *im,
|
||||
const SDL_TextInputEvent *event);
|
||||
|
||||
void
|
||||
input_manager_process_key(struct input_manager *im,
|
||||
const SDL_KeyboardEvent *event);
|
||||
|
||||
void
|
||||
input_manager_process_mouse_motion(struct input_manager *im,
|
||||
const SDL_MouseMotionEvent *event);
|
||||
|
||||
void
|
||||
input_manager_process_touch(struct input_manager *im,
|
||||
const SDL_TouchFingerEvent *event);
|
||||
|
||||
void
|
||||
input_manager_process_mouse_button(struct input_manager *im,
|
||||
const SDL_MouseButtonEvent *event);
|
||||
|
||||
void
|
||||
input_manager_process_mouse_wheel(struct input_manager *im,
|
||||
const SDL_MouseWheelEvent *event);
|
||||
bool
|
||||
input_manager_handle_event(struct input_manager *im, SDL_Event *event);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,28 +29,8 @@
|
||||
#include "util/log.h"
|
||||
#include "util/net.h"
|
||||
|
||||
static const char *sc_scale_filter_names[SC_SCALE_FILTER__COUNT] = {
|
||||
[SC_SCALE_FILTER_NONE] = "none",
|
||||
[SC_SCALE_FILTER_TRILINEAR] = "trilinear",
|
||||
[SC_SCALE_FILTER_BILINEAR] = "bilinear",
|
||||
[SC_SCALE_FILTER_BICUBIC] = "bicubic",
|
||||
[SC_SCALE_FILTER_X] = "x",
|
||||
[SC_SCALE_FILTER_POINT] = "point",
|
||||
[SC_SCALE_FILTER_AREA] = "area",
|
||||
[SC_SCALE_FILTER_BICUBLIN] = "bicublin",
|
||||
[SC_SCALE_FILTER_GAUSS] = "gauss",
|
||||
[SC_SCALE_FILTER_SINC] = "sinc",
|
||||
[SC_SCALE_FILTER_LANCZOS] = "lanczos",
|
||||
[SC_SCALE_FILTER_SPLINE] = "spline",
|
||||
};
|
||||
|
||||
const char *
|
||||
sc_scale_filter_name(enum sc_scale_filter scale_filter) {
|
||||
return sc_scale_filter_names[scale_filter];
|
||||
}
|
||||
|
||||
static struct server server;
|
||||
static struct screen screen = SCREEN_INITIALIZER;
|
||||
static struct screen screen;
|
||||
static struct fps_counter fps_counter;
|
||||
static struct video_buffer video_buffer;
|
||||
static struct stream stream;
|
||||
@@ -193,56 +173,6 @@ handle_event(SDL_Event *event, const struct scrcpy_options *options) {
|
||||
case SDL_QUIT:
|
||||
LOGD("User requested to quit");
|
||||
return EVENT_RESULT_STOPPED_BY_USER;
|
||||
case EVENT_NEW_FRAME:
|
||||
if (!screen.has_frame) {
|
||||
screen.has_frame = true;
|
||||
// this is the very first frame, show the window
|
||||
screen_show_window(&screen);
|
||||
}
|
||||
if (!screen_update_frame(&screen, &video_buffer)) {
|
||||
return EVENT_RESULT_CONTINUE;
|
||||
}
|
||||
break;
|
||||
case SDL_WINDOWEVENT:
|
||||
if (screen.has_frame) {
|
||||
screen_handle_window_event(&screen, &event->window);
|
||||
}
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
if (!options->control) {
|
||||
break;
|
||||
}
|
||||
input_manager_process_text_input(&input_manager, &event->text);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
// some key events do not interact with the device, so process the
|
||||
// event even if control is disabled
|
||||
input_manager_process_key(&input_manager, &event->key);
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (!options->control) {
|
||||
break;
|
||||
}
|
||||
input_manager_process_mouse_motion(&input_manager, &event->motion);
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
if (!options->control) {
|
||||
break;
|
||||
}
|
||||
input_manager_process_mouse_wheel(&input_manager, &event->wheel);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
// some mouse events do not interact with the device, so process
|
||||
// the event even if control is disabled
|
||||
input_manager_process_mouse_button(&input_manager, &event->button);
|
||||
break;
|
||||
case SDL_FINGERMOTION:
|
||||
case SDL_FINGERDOWN:
|
||||
case SDL_FINGERUP:
|
||||
input_manager_process_touch(&input_manager, &event->tfinger);
|
||||
break;
|
||||
case SDL_DROPFILE: {
|
||||
if (!options->control) {
|
||||
break;
|
||||
@@ -264,6 +194,16 @@ handle_event(SDL_Event *event, const struct scrcpy_options *options) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool consumed = screen_handle_event(&screen, event);
|
||||
if (consumed) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
consumed = input_manager_handle_event(&input_manager, event);
|
||||
(void) consumed;
|
||||
|
||||
end:
|
||||
return EVENT_RESULT_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -326,6 +266,14 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
|
||||
free(local_fmt);
|
||||
}
|
||||
|
||||
static void
|
||||
decoder_on_new_frame(struct decoder *decoder, void *userdata) {
|
||||
(void) decoder;
|
||||
(void) userdata;
|
||||
|
||||
screen_on_new_frame(&screen);
|
||||
}
|
||||
|
||||
bool
|
||||
scrcpy(const struct scrcpy_options *options) {
|
||||
if (!server_init(&server)) {
|
||||
@@ -406,7 +354,11 @@ scrcpy(const struct scrcpy_options *options) {
|
||||
file_handler_initialized = true;
|
||||
}
|
||||
|
||||
decoder_init(&decoder, &video_buffer);
|
||||
static const struct decoder_callbacks decoder_cbs = {
|
||||
.on_new_frame = decoder_on_new_frame,
|
||||
};
|
||||
|
||||
decoder_init(&decoder, &video_buffer, &decoder_cbs, NULL);
|
||||
dec = &decoder;
|
||||
}
|
||||
|
||||
@@ -449,6 +401,8 @@ scrcpy(const struct scrcpy_options *options) {
|
||||
const char *window_title =
|
||||
options->window_title ? options->window_title : device_name;
|
||||
|
||||
screen_init(&screen, &video_buffer);
|
||||
|
||||
if (!screen_init_rendering(&screen, window_title, frame_size,
|
||||
options->always_on_top, options->window_x,
|
||||
options->window_y, options->window_width,
|
||||
|
||||
@@ -44,22 +44,8 @@ struct sc_port_range {
|
||||
enum sc_scale_filter {
|
||||
SC_SCALE_FILTER_NONE,
|
||||
SC_SCALE_FILTER_TRILINEAR, // mipmaps
|
||||
SC_SCALE_FILTER_BILINEAR,
|
||||
SC_SCALE_FILTER_BICUBIC,
|
||||
SC_SCALE_FILTER_X,
|
||||
SC_SCALE_FILTER_POINT,
|
||||
SC_SCALE_FILTER_AREA,
|
||||
SC_SCALE_FILTER_BICUBLIN,
|
||||
SC_SCALE_FILTER_GAUSS,
|
||||
SC_SCALE_FILTER_SINC,
|
||||
SC_SCALE_FILTER_LANCZOS,
|
||||
SC_SCALE_FILTER_SPLINE,
|
||||
SC_SCALE_FILTER__COUNT,
|
||||
};
|
||||
|
||||
const char *
|
||||
sc_scale_filter_name(enum sc_scale_filter scale_filter);
|
||||
|
||||
#define SC_WINDOW_POSITION_UNDEFINED (-0x8000)
|
||||
|
||||
struct scrcpy_options {
|
||||
|
||||
220
app/src/screen.c
220
app/src/screen.c
@@ -4,6 +4,7 @@
|
||||
#include <string.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "events.h"
|
||||
#include "icon.xpm"
|
||||
#include "tiny_xpm.h"
|
||||
#include "video_buffer.h"
|
||||
@@ -190,8 +191,36 @@ screen_update_content_rect(struct screen *screen) {
|
||||
}
|
||||
|
||||
void
|
||||
screen_init(struct screen *screen) {
|
||||
screen_init(struct screen *screen, struct video_buffer *vb) {
|
||||
*screen = (struct screen) SCREEN_INITIALIZER;
|
||||
screen->vb = vb;
|
||||
}
|
||||
|
||||
static inline SDL_Texture *
|
||||
create_texture(struct screen *screen) {
|
||||
SDL_Renderer *renderer = screen->renderer;
|
||||
struct size size = screen->frame_size;
|
||||
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
size.width, size.height);
|
||||
if (!texture) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (screen->mipmaps) {
|
||||
struct sc_opengl *gl = &screen->gl;
|
||||
|
||||
SDL_GL_BindTexture(texture, NULL, NULL);
|
||||
|
||||
// Enable trilinear filtering for downscaling
|
||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
gl->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -1.f);
|
||||
|
||||
SDL_GL_UnbindTexture(texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -246,13 +275,36 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = sc_frame_texture_init(&screen->ftex, screen->renderer,
|
||||
scale_filter, frame_size);
|
||||
if (!ok) {
|
||||
LOGC("Could not init frame texture");
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
return false;
|
||||
SDL_RendererInfo renderer_info;
|
||||
int r = SDL_GetRendererInfo(screen->renderer, &renderer_info);
|
||||
const char *renderer_name = r ? NULL : renderer_info.name;
|
||||
LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)");
|
||||
|
||||
// starts with "opengl"
|
||||
bool use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
|
||||
bool mipmaps = scale_filter == SC_SCALE_FILTER_TRILINEAR;
|
||||
if (use_opengl) {
|
||||
struct sc_opengl *gl = &screen->gl;
|
||||
sc_opengl_init(gl);
|
||||
|
||||
LOGI("OpenGL version: %s", gl->version);
|
||||
|
||||
if (mipmaps) {
|
||||
bool supports_mipmaps =
|
||||
sc_opengl_version_at_least(gl, 3, 0, /* OpenGL 3.0+ */
|
||||
2, 0 /* OpenGL ES 2.0+ */);
|
||||
if (supports_mipmaps) {
|
||||
LOGI("Trilinear filtering enabled");
|
||||
screen->mipmaps = true;
|
||||
} else {
|
||||
LOGW("Trilinear filtering disabled "
|
||||
"(OpenGL 3.0+ or ES 2.0+ required)");
|
||||
}
|
||||
} else {
|
||||
LOGI("Trilinear filtering disabled");
|
||||
}
|
||||
} else if (mipmaps) {
|
||||
LOGD("Trilinear filtering disabled (not an OpenGL renderer)");
|
||||
}
|
||||
|
||||
SDL_Surface *icon = read_xpm(icon_xpm);
|
||||
@@ -263,6 +315,17 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
LOGW("Could not load icon");
|
||||
}
|
||||
|
||||
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width,
|
||||
frame_size.height);
|
||||
screen->texture = create_texture(screen);
|
||||
if (!screen->texture) {
|
||||
LOGC("Could not create texture: %s", SDL_GetError());
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
screen_destroy(screen);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset the window size to trigger a SIZE_CHANGED event, to workaround
|
||||
// HiDPI issues with some SDL renderers when several displays having
|
||||
// different HiDPI scaling are connected
|
||||
@@ -280,7 +343,9 @@ screen_show_window(struct screen *screen) {
|
||||
|
||||
void
|
||||
screen_destroy(struct screen *screen) {
|
||||
sc_frame_texture_destroy(&screen->ftex);
|
||||
if (screen->texture) {
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
}
|
||||
SDL_DestroyRenderer(screen->renderer);
|
||||
SDL_DestroyWindow(screen->window);
|
||||
}
|
||||
@@ -343,10 +408,13 @@ screen_set_rotation(struct screen *screen, unsigned rotation) {
|
||||
}
|
||||
|
||||
// recreate the texture and resize the window if the frame size has changed
|
||||
static void
|
||||
static bool
|
||||
prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
||||
if (screen->frame_size.width != new_frame_size.width
|
||||
|| screen->frame_size.height != new_frame_size.height) {
|
||||
// frame dimension changed, destroy texture
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
|
||||
screen->frame_size = new_frame_size;
|
||||
|
||||
struct size new_content_size =
|
||||
@@ -354,20 +422,42 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
||||
set_content_size(screen, new_content_size);
|
||||
|
||||
screen_update_content_rect(screen);
|
||||
|
||||
LOGI("New texture: %" PRIu16 "x%" PRIu16,
|
||||
screen->frame_size.width, screen->frame_size.height);
|
||||
screen->texture = create_texture(screen);
|
||||
if (!screen->texture) {
|
||||
LOGC("Could not create texture: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// write the frame into the texture
|
||||
static void
|
||||
update_texture(struct screen *screen, const AVFrame *frame) {
|
||||
SDL_UpdateYUVTexture(screen->texture, NULL,
|
||||
frame->data[0], frame->linesize[0],
|
||||
frame->data[1], frame->linesize[1],
|
||||
frame->data[2], frame->linesize[2]);
|
||||
|
||||
if (screen->mipmaps) {
|
||||
SDL_GL_BindTexture(screen->texture, NULL, NULL);
|
||||
screen->gl.GenerateMipmap(GL_TEXTURE_2D);
|
||||
SDL_GL_UnbindTexture(screen->texture);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
screen_update_frame(struct screen *screen, struct video_buffer *vb) {
|
||||
const AVFrame *frame = video_buffer_take_rendering_frame(vb);
|
||||
static bool
|
||||
screen_update_frame(struct screen *screen) {
|
||||
const AVFrame *frame = video_buffer_take_rendering_frame(screen->vb);
|
||||
struct size new_frame_size = {frame->width, frame->height};
|
||||
prepare_for_frame(screen, new_frame_size);
|
||||
|
||||
struct size rect_size = {screen->rect.w, screen->rect.h};
|
||||
bool ok = sc_frame_texture_update(&screen->ftex, frame, rect_size);
|
||||
if (!ok) {
|
||||
if (!prepare_for_frame(screen, new_frame_size)) {
|
||||
return false;
|
||||
}
|
||||
update_texture(screen, frame);
|
||||
|
||||
screen_render(screen, false);
|
||||
return true;
|
||||
@@ -377,18 +467,11 @@ void
|
||||
screen_render(struct screen *screen, bool update_content_rect) {
|
||||
if (update_content_rect) {
|
||||
screen_update_content_rect(screen);
|
||||
struct size rect_size = {screen->rect.w, screen->rect.h};
|
||||
if (!sc_frame_texture_resize(&screen->ftex, rect_size)) {
|
||||
// FIXME return error
|
||||
LOGC("oops");
|
||||
}
|
||||
}
|
||||
|
||||
struct sc_frame_texture *ftex = &screen->ftex;
|
||||
SDL_RenderClear(ftex->renderer);
|
||||
SDL_RenderClear(screen->renderer);
|
||||
if (screen->rotation == 0) {
|
||||
SDL_RenderCopy(screen->renderer, ftex->texture, NULL,
|
||||
&screen->rect);
|
||||
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &screen->rect);
|
||||
} else {
|
||||
// rotation in RenderCopyEx() is clockwise, while screen->rotation is
|
||||
// counterclockwise (to be consistent with --lock-video-orientation)
|
||||
@@ -408,10 +491,10 @@ screen_render(struct screen *screen, bool update_content_rect) {
|
||||
dstrect = &screen->rect;
|
||||
}
|
||||
|
||||
SDL_RenderCopyEx(screen->renderer, ftex->texture, NULL, dstrect,
|
||||
SDL_RenderCopyEx(screen->renderer, screen->texture, NULL, dstrect,
|
||||
angle, NULL, 0);
|
||||
}
|
||||
SDL_RenderPresent(ftex->renderer);
|
||||
SDL_RenderPresent(screen->renderer);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -461,31 +544,52 @@ screen_resize_to_pixel_perfect(struct screen *screen) {
|
||||
content_size.height);
|
||||
}
|
||||
|
||||
void
|
||||
screen_handle_window_event(struct screen *screen,
|
||||
const SDL_WindowEvent *event) {
|
||||
switch (event->event) {
|
||||
case SDL_WINDOWEVENT_EXPOSED:
|
||||
screen_render(screen, true);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
screen_render(screen, true);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||
screen->maximized = true;
|
||||
break;
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
if (screen->fullscreen) {
|
||||
// On Windows, in maximized+fullscreen, disabling fullscreen
|
||||
// mode unexpectedly triggers the "restored" then "maximized"
|
||||
// events, leaving the window in a weird state (maximized
|
||||
// according to the events, but not maximized visually).
|
||||
break;
|
||||
bool
|
||||
screen_handle_event(struct screen *screen, SDL_Event *event) {
|
||||
switch (event->type) {
|
||||
case EVENT_NEW_FRAME:
|
||||
if (!screen->has_frame) {
|
||||
screen->has_frame = true;
|
||||
// this is the very first frame, show the window
|
||||
screen_show_window(screen);
|
||||
}
|
||||
screen->maximized = false;
|
||||
apply_pending_resize(screen);
|
||||
break;
|
||||
bool ok = screen_update_frame(screen);
|
||||
if (!ok) {
|
||||
LOGW("Frame update failed\n");
|
||||
}
|
||||
return true;
|
||||
case SDL_WINDOWEVENT:
|
||||
if (!screen->has_frame) {
|
||||
// Do nothing
|
||||
return true;
|
||||
}
|
||||
switch (event->window.event) {
|
||||
case SDL_WINDOWEVENT_EXPOSED:
|
||||
screen_render(screen, true);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
screen_render(screen, true);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||
screen->maximized = true;
|
||||
break;
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
if (screen->fullscreen) {
|
||||
// On Windows, in maximized+fullscreen, disabling
|
||||
// fullscreen mode unexpectedly triggers the "restored"
|
||||
// then "maximized" events, leaving the window in a
|
||||
// weird state (maximized according to the events, but
|
||||
// not maximized visually).
|
||||
break;
|
||||
}
|
||||
screen->maximized = false;
|
||||
apply_pending_resize(screen);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct point
|
||||
@@ -543,3 +647,15 @@ screen_hidpi_scale_coords(struct screen *screen, int32_t *x, int32_t *y) {
|
||||
*x = (int64_t) *x * dw / ww;
|
||||
*y = (int64_t) *y * dh / wh;
|
||||
}
|
||||
|
||||
void
|
||||
screen_on_new_frame(struct screen *screen) {
|
||||
(void) screen;
|
||||
|
||||
static SDL_Event new_frame_event = {
|
||||
.type = EVENT_NEW_FRAME,
|
||||
};
|
||||
|
||||
// Post the event on the UI thread
|
||||
SDL_PushEvent(&new_frame_event);
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include "coords.h"
|
||||
#include "frame_texture.h"
|
||||
#include "opengl.h"
|
||||
#include "scrcpy.h"
|
||||
|
||||
struct video_buffer;
|
||||
|
||||
struct screen {
|
||||
struct video_buffer *vb;
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
struct sc_frame_texture ftex;
|
||||
|
||||
SDL_Texture *texture;
|
||||
struct sc_opengl gl;
|
||||
struct size frame_size;
|
||||
struct size content_size; // rotated frame_size
|
||||
|
||||
@@ -35,12 +35,15 @@ struct screen {
|
||||
bool fullscreen;
|
||||
bool maximized;
|
||||
bool no_window;
|
||||
bool mipmaps;
|
||||
};
|
||||
|
||||
#define SCREEN_INITIALIZER { \
|
||||
.vb = NULL, \
|
||||
.window = NULL, \
|
||||
.renderer = NULL, \
|
||||
.ftex = {0}, \
|
||||
.texture = NULL, \
|
||||
.gl = {0}, \
|
||||
.frame_size = { \
|
||||
.width = 0, \
|
||||
.height = 0, \
|
||||
@@ -65,11 +68,12 @@ struct screen {
|
||||
.fullscreen = false, \
|
||||
.maximized = false, \
|
||||
.no_window = false, \
|
||||
.mipmaps = false, \
|
||||
}
|
||||
|
||||
// initialize default values
|
||||
void
|
||||
screen_init(struct screen *screen);
|
||||
screen_init(struct screen *screen, struct video_buffer *vb);
|
||||
|
||||
// initialize screen, create window, renderer and texture (window is hidden)
|
||||
// window_x and window_y accept SC_WINDOW_POSITION_UNDEFINED
|
||||
@@ -88,10 +92,6 @@ screen_show_window(struct screen *screen);
|
||||
void
|
||||
screen_destroy(struct screen *screen);
|
||||
|
||||
// resize if necessary and write the rendered frame into the texture
|
||||
bool
|
||||
screen_update_frame(struct screen *screen, struct video_buffer *vb);
|
||||
|
||||
// render the texture to the renderer
|
||||
//
|
||||
// Set the update_content_rect flag if the window or content size may have
|
||||
@@ -115,9 +115,9 @@ screen_resize_to_pixel_perfect(struct screen *screen);
|
||||
void
|
||||
screen_set_rotation(struct screen *screen, unsigned rotation);
|
||||
|
||||
// react to window events
|
||||
void
|
||||
screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *event);
|
||||
// react to SDL events
|
||||
bool
|
||||
screen_handle_event(struct screen *screen, SDL_Event *event);
|
||||
|
||||
// convert point from window coordinates to frame coordinates
|
||||
// x and y are expressed in pixels
|
||||
@@ -138,4 +138,9 @@ screen_convert_drawable_to_frame_coords(struct screen *screen,
|
||||
void
|
||||
screen_hidpi_scale_coords(struct screen *screen, int32_t *x, int32_t *y);
|
||||
|
||||
// Notify the screen that a new frame is available in the video_buffer.
|
||||
// Called from a separate thread.
|
||||
void
|
||||
screen_on_new_frame(struct screen *screen);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -375,8 +375,6 @@ server_init(struct server *server) {
|
||||
server->video_socket = INVALID_SOCKET;
|
||||
server->control_socket = INVALID_SOCKET;
|
||||
|
||||
server->port_range.first = 0;
|
||||
server->port_range.last = 0;
|
||||
server->local_port = 0;
|
||||
|
||||
server->tunnel_enabled = false;
|
||||
@@ -410,8 +408,6 @@ run_wait_server(void *data) {
|
||||
bool
|
||||
server_start(struct server *server, const char *serial,
|
||||
const struct server_params *params) {
|
||||
server->port_range = params->port_range;
|
||||
|
||||
if (serial) {
|
||||
server->serial = strdup(serial);
|
||||
if (!server->serial) {
|
||||
|
||||
@@ -26,7 +26,6 @@ struct server {
|
||||
socket_t server_socket; // only used if !tunnel_forward
|
||||
socket_t video_socket;
|
||||
socket_t control_socket;
|
||||
struct sc_port_range port_range;
|
||||
uint16_t local_port; // selected from port_range
|
||||
bool tunnel_enabled;
|
||||
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
||||
|
||||
@@ -4,6 +4,7 @@ project('scrcpy', 'c',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
'warning_level=2',
|
||||
'b_ndebug=if-release',
|
||||
])
|
||||
|
||||
if get_option('compile_app')
|
||||
|
||||
Reference in New Issue
Block a user