Compare commits

..

20 Commits

Author SHA1 Message Date
Romain Vimont
ca3d807e7f Use non-secure display for Android >= 12
Since Android 12, secure displays could not be created with shell
permissions anymore.

Refs commit 1fdde490fd
Fixes #2129 <https://github.com/Genymobile/scrcpy/issues/2129>
2021-02-19 17:26:40 +01:00
Romain Vimont
dce0867737 Enable NDEBUG via Meson built-in option 2021-02-17 09:54:03 +01:00
Romain Vimont
5c4c28c973 Handle im-related events from input_manager.c 2021-02-17 09:54:03 +01:00
Romain Vimont
98628f25b5 Inline window events handling
Now that all screen-related events are handled from screen.c, there is
no need for a separate method for window events.
2021-02-17 09:54:03 +01:00
Romain Vimont
e1dbe4f71c Handle screen-related events from screen.c 2021-02-17 09:54:03 +01:00
Romain Vimont
b1734ab737 Reference video buffer from screen
This paves the way to handle EVENT_NEW_FRAME from screen.c, by allowing
to call screen_update_frame() without an explicit video_buffer instance.
2021-02-17 09:54:03 +01:00
Romain Vimont
44aa7f2c88 Improve error handling in screen initialization
After the struct screen is initialized, the window and the renderer are
necessarily valid, so there is no need o check in screen_destroy().
2021-02-17 09:54:03 +01:00
Romain Vimont
626094ad13 Handle window events only once visible
This will avoid corner cases where we need to resize while no frame has
been received yet.
2021-02-17 09:54:03 +01:00
Romain Vimont
a566635c43 Log mipmaps error only if mipmaps are enabled 2021-02-17 09:54:03 +01:00
Romain Vimont
862948b132 Make use_opengl local
The flag is used only locally, there is no need to store it in the
screen structure.
2021-02-17 09:54:03 +01:00
Romain Vimont
c0c4ba7009 Add intermediate frame in video buffer
There were only two frames simultaneously:
 - one used by the decoder;
 - one used by the renderer.

When the decoder finished decoding a frame, it swapped it with the
rendering frame.

Adding a third frame provides several benefits:
 - the decoder do not have to wait for the renderer to release the
   mutex;
 - it simplifies the video_buffer API;
 - it makes the rendering frame valid until the next call to
   video_buffer_take_rendering_frame(), which will be useful for
   swscaling on window resize.
2021-02-17 09:54:03 +01:00
Romain Vimont
c53bd4d8b6 Assert non-recursive usage of mutexes 2021-02-17 09:54:03 +01:00
Romain Vimont
54f5c42d7b Add mutex assertions 2021-02-17 09:54:03 +01:00
Romain Vimont
21d206f360 Expose mutex assertions
Add a function to assert that the mutex is held (or not).
2021-02-17 09:54:03 +01:00
Romain Vimont
d2689fc168 Expose thread id 2021-02-17 09:54:03 +01:00
Romain Vimont
f6320c7e31 Wrap SDL thread functions into scrcpy-specific API
The goal is to expose a consistent API for system tools, and paves the
way to make the "core" independant of SDL in the future.
2021-02-17 09:54:03 +01:00
Romain Vimont
30e619d37f Replace SDL_strdup() by strdup()
The functions SDL_malloc(), SDL_free() and SDL_strdup() were used only
because strdup() was not available everywhere.

Now that it is available, use the native version of these functions.
2021-02-17 09:54:03 +01:00
Romain Vimont
c0dde0fade Provide strdup() compat
Make strdup() available on all platforms.
2021-02-17 09:53:25 +01:00
Romain Vimont
ace438e52a Remove unused port_range field
The port_range is used from "struct server_params", the copy in
"struct server" was unused.
2021-02-14 14:47:49 +01:00
Romain Vimont
8e83f3e8af Remove unused custom event 2021-02-14 14:44:05 +01:00
17 changed files with 251 additions and 573 deletions

View File

@@ -11,7 +11,6 @@ src = [
'src/event_converter.c', 'src/event_converter.c',
'src/file_handler.c', 'src/file_handler.c',
'src/fps_counter.c', 'src/fps_counter.c',
'src/frame_texture.c',
'src/input_manager.c', 'src/input_manager.c',
'src/opengl.c', 'src/opengl.c',
'src/receiver.c', 'src/receiver.c',
@@ -47,7 +46,6 @@ if not get_option('crossbuild_windows')
dependency('libavformat'), dependency('libavformat'),
dependency('libavcodec'), dependency('libavcodec'),
dependency('libavutil'), dependency('libavutil'),
dependency('libswscale'),
dependency('sdl2'), dependency('sdl2'),
] ]
@@ -101,9 +99,6 @@ foreach f : check_functions
endif endif
endforeach endforeach
# expose the build type
conf.set('NDEBUG', get_option('buildtype') != 'debug')
# the version, updated on release # the version, updated on release
conf.set_quoted('SCRCPY_VERSION', meson.project_version()) conf.set_quoted('SCRCPY_VERSION', meson.project_version())

View File

@@ -167,13 +167,6 @@ Set the initial display rotation. Possibles values are 0, 1, 2 and 3. Each incre
.BI "\-s, \-\-serial " number .BI "\-s, \-\-serial " number
The device serial number. Mandatory only if several devices are connected to adb. The device serial number. Mandatory only if several devices are connected to adb.
.TP
.BI "\-\-scale\-filter filter
Supported filters are "none" and "trilinear".
Trilinear filtering is only available if the renderer is OpenGL 3.0+ or OpenGL
ES 2.0+.
.TP .TP
.BI "\-\-shortcut\-mod " key[+...]][,...] .BI "\-\-shortcut\-mod " key[+...]][,...]
Specify the modifiers to use for scrcpy shortcuts. Possible keys are "lctrl", "rctrl", "lalt", "ralt", "lsuper" and "rsuper". Specify the modifiers to use for scrcpy shortcuts. Possible keys are "lctrl", "rctrl", "lalt", "ralt", "lsuper" and "rsuper".

View File

@@ -103,6 +103,11 @@ scrcpy_print_usage(const char *arg0) {
" --no-key-repeat\n" " --no-key-repeat\n"
" Do not forward repeated key events when a key is held down.\n" " Do not forward repeated key events when a key is held down.\n"
"\n" "\n"
" --no-mipmaps\n"
" If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then\n"
" mipmaps are automatically generated to improve downscaling\n"
" quality. This option disables the generation of mipmaps.\n"
"\n"
" -p, --port port[:port]\n" " -p, --port port[:port]\n"
" Set the TCP port (range) used by the client to listen.\n" " Set the TCP port (range) used by the client to listen.\n"
" Default is %d:%d.\n" " Default is %d:%d.\n"
@@ -149,11 +154,6 @@ scrcpy_print_usage(const char *arg0) {
" The device serial number. Mandatory only if several devices\n" " The device serial number. Mandatory only if several devices\n"
" are connected to adb.\n" " are connected to adb.\n"
"\n" "\n"
" --scale-filter filter\n"
" Supported filters are \"none\" and \"trilinear\".\n"
" Trilinear filtering is only available if the renderer is\n"
" OpenGL 3.0+ or OpenGL ES 2.0+.\n"
"\n"
" --shortcut-mod key[+...]][,...]\n" " --shortcut-mod key[+...]][,...]\n"
" Specify the modifiers to use for scrcpy shortcuts.\n" " Specify the modifiers to use for scrcpy shortcuts.\n"
" Possible keys are \"lctrl\", \"rctrl\", \"lalt\", \"ralt\",\n" " Possible keys are \"lctrl\", \"rctrl\", \"lalt\", \"ralt\",\n"
@@ -641,62 +641,6 @@ guess_record_format(const char *filename) {
return 0; return 0;
} }
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;
}
if (!strcmp(optarg, "trilinear")) {
*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);
return false;
}
#define OPT_RENDER_EXPIRED_FRAMES 1000 #define OPT_RENDER_EXPIRED_FRAMES 1000
#define OPT_WINDOW_TITLE 1001 #define OPT_WINDOW_TITLE 1001
#define OPT_PUSH_TARGET 1002 #define OPT_PUSH_TARGET 1002
@@ -723,7 +667,6 @@ parse_scale_filter(const char *optarg, enum sc_scale_filter *filter) {
#define OPT_FORWARD_ALL_CLICKS 1023 #define OPT_FORWARD_ALL_CLICKS 1023
#define OPT_LEGACY_PASTE 1024 #define OPT_LEGACY_PASTE 1024
#define OPT_ENCODER_NAME 1025 #define OPT_ENCODER_NAME 1025
#define OPT_SCALE_FILTER 1026
bool bool
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
@@ -760,7 +703,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"render-expired-frames", no_argument, NULL, {"render-expired-frames", no_argument, NULL,
OPT_RENDER_EXPIRED_FRAMES}, OPT_RENDER_EXPIRED_FRAMES},
{"rotation", required_argument, NULL, OPT_ROTATION}, {"rotation", required_argument, NULL, OPT_ROTATION},
{"scale-filter", required_argument, NULL, OPT_SCALE_FILTER},
{"serial", required_argument, NULL, 's'}, {"serial", required_argument, NULL, 's'},
{"shortcut-mod", required_argument, NULL, OPT_SHORTCUT_MOD}, {"shortcut-mod", required_argument, NULL, OPT_SHORTCUT_MOD},
{"show-touches", no_argument, NULL, 't'}, {"show-touches", no_argument, NULL, 't'},
@@ -915,9 +857,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
opts->render_driver = optarg; opts->render_driver = optarg;
break; break;
case OPT_NO_MIPMAPS: case OPT_NO_MIPMAPS:
LOGW("Deprecated option --no-mipmaps. " opts->mipmaps = false;
"Use --scale-filter=none instead.");
opts->scale_filter = SC_SCALE_FILTER_NONE;
break; break;
case OPT_NO_KEY_REPEAT: case OPT_NO_KEY_REPEAT:
opts->forward_key_repeat = false; opts->forward_key_repeat = false;
@@ -945,11 +885,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
case OPT_LEGACY_PASTE: case OPT_LEGACY_PASTE:
opts->legacy_paste = true; opts->legacy_paste = true;
break; break;
case OPT_SCALE_FILTER:
if (!parse_scale_filter(optarg, &opts->scale_filter)) {
return false;
}
break;
default: default:
// getopt prints the error message on stderr // getopt prints the error message on stderr
return false; return false;

View File

@@ -56,7 +56,7 @@
# define SCRCPY_SDL_HAS_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR # define SCRCPY_SDL_HAS_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
#endif #endif
#ifdef HAVE_STRDUP #ifndef HAVE_STRDUP
char *strdup(const char *s); char *strdup(const char *s);
#endif #endif

View File

@@ -1,3 +1,2 @@
#define EVENT_NEW_SESSION SDL_USEREVENT #define EVENT_NEW_FRAME SDL_USEREVENT
#define EVENT_NEW_FRAME (SDL_USEREVENT + 1) #define EVENT_STREAM_STOPPED (SDL_USEREVENT + 1)
#define EVENT_STREAM_STOPPED (SDL_USEREVENT + 2)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -286,7 +286,7 @@ rotate_client_right(struct screen *screen) {
screen_set_rotation(screen, new_rotation); screen_set_rotation(screen, new_rotation);
} }
void static void
input_manager_process_text_input(struct input_manager *im, input_manager_process_text_input(struct input_manager *im,
const SDL_TextInputEvent *event) { const SDL_TextInputEvent *event) {
if (is_shortcut_mod(im, SDL_GetModState())) { if (is_shortcut_mod(im, SDL_GetModState())) {
@@ -366,7 +366,7 @@ convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to,
return true; return true;
} }
void static void
input_manager_process_key(struct input_manager *im, input_manager_process_key(struct input_manager *im,
const SDL_KeyboardEvent *event) { const SDL_KeyboardEvent *event) {
// control: indicates the state of the command-line option --no-control // 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; return true;
} }
void static void
input_manager_process_mouse_motion(struct input_manager *im, input_manager_process_mouse_motion(struct input_manager *im,
const SDL_MouseMotionEvent *event) { const SDL_MouseMotionEvent *event) {
if (!event->state) { if (!event->state) {
@@ -605,7 +605,7 @@ convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen,
return true; return true;
} }
void static void
input_manager_process_touch(struct input_manager *im, input_manager_process_touch(struct input_manager *im,
const SDL_TouchFingerEvent *event) { const SDL_TouchFingerEvent *event) {
struct control_msg msg; struct control_msg msg;
@@ -637,7 +637,7 @@ convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen,
return true; return true;
} }
void static void
input_manager_process_mouse_button(struct input_manager *im, input_manager_process_mouse_button(struct input_manager *im,
const SDL_MouseButtonEvent *event) { const SDL_MouseButtonEvent *event) {
bool control = im->control; bool control = im->control;
@@ -736,7 +736,7 @@ convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen,
return true; return true;
} }
void static void
input_manager_process_mouse_wheel(struct input_manager *im, input_manager_process_mouse_wheel(struct input_manager *im,
const SDL_MouseWheelEvent *event) { const SDL_MouseWheelEvent *event) {
struct control_msg msg; 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;
}

View File

@@ -40,28 +40,7 @@ void
input_manager_init(struct input_manager *im, input_manager_init(struct input_manager *im,
const struct scrcpy_options *options); const struct scrcpy_options *options);
void bool
input_manager_process_text_input(struct input_manager *im, input_manager_handle_event(struct input_manager *im, SDL_Event *event);
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);
#endif #endif

View File

@@ -29,28 +29,8 @@
#include "util/log.h" #include "util/log.h"
#include "util/net.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 server server;
static struct screen screen = SCREEN_INITIALIZER; static struct screen screen;
static struct fps_counter fps_counter; 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;
@@ -193,56 +173,6 @@ handle_event(SDL_Event *event, const struct scrcpy_options *options) {
case SDL_QUIT: case SDL_QUIT:
LOGD("User requested to quit"); LOGD("User requested to quit");
return EVENT_RESULT_STOPPED_BY_USER; 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: { case SDL_DROPFILE: {
if (!options->control) { if (!options->control) {
break; break;
@@ -264,6 +194,16 @@ handle_event(SDL_Event *event, const struct scrcpy_options *options) {
break; 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; return EVENT_RESULT_CONTINUE;
} }
@@ -449,12 +389,14 @@ scrcpy(const struct scrcpy_options *options) {
const char *window_title = const char *window_title =
options->window_title ? options->window_title : device_name; options->window_title ? options->window_title : device_name;
screen_init(&screen, &video_buffer);
if (!screen_init_rendering(&screen, window_title, frame_size, if (!screen_init_rendering(&screen, window_title, frame_size,
options->always_on_top, options->window_x, options->always_on_top, options->window_x,
options->window_y, options->window_width, options->window_y, options->window_width,
options->window_height, options->window_height,
options->window_borderless, options->window_borderless,
options->rotation, options->scale_filter)) { options->rotation, options->mipmaps)) {
goto end; goto end;
} }

View File

@@ -41,25 +41,6 @@ struct sc_port_range {
uint16_t last; uint16_t last;
}; };
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) #define SC_WINDOW_POSITION_UNDEFINED (-0x8000)
struct scrcpy_options { struct scrcpy_options {
@@ -75,7 +56,6 @@ struct scrcpy_options {
enum sc_record_format record_format; enum sc_record_format record_format;
struct sc_port_range port_range; struct sc_port_range port_range;
struct sc_shortcut_mods shortcut_mods; struct sc_shortcut_mods shortcut_mods;
enum sc_scale_filter scale_filter;
uint16_t max_size; uint16_t max_size;
uint32_t bit_rate; uint32_t bit_rate;
uint16_t max_fps; uint16_t max_fps;
@@ -95,6 +75,7 @@ struct scrcpy_options {
bool render_expired_frames; bool render_expired_frames;
bool prefer_text; bool prefer_text;
bool window_borderless; bool window_borderless;
bool mipmaps;
bool stay_awake; bool stay_awake;
bool force_adb_forward; bool force_adb_forward;
bool disable_screensaver; bool disable_screensaver;
@@ -122,7 +103,6 @@ struct scrcpy_options {
.data = {SC_MOD_LALT, SC_MOD_LSUPER}, \ .data = {SC_MOD_LALT, SC_MOD_LSUPER}, \
.count = 2, \ .count = 2, \
}, \ }, \
.scale_filter = SC_SCALE_FILTER_TRILINEAR, \
.max_size = DEFAULT_MAX_SIZE, \ .max_size = DEFAULT_MAX_SIZE, \
.bit_rate = DEFAULT_BIT_RATE, \ .bit_rate = DEFAULT_BIT_RATE, \
.max_fps = 0, \ .max_fps = 0, \
@@ -142,6 +122,7 @@ struct scrcpy_options {
.render_expired_frames = false, \ .render_expired_frames = false, \
.prefer_text = false, \ .prefer_text = false, \
.window_borderless = false, \ .window_borderless = false, \
.mipmaps = true, \
.stay_awake = false, \ .stay_awake = false, \
.force_adb_forward = false, \ .force_adb_forward = false, \
.disable_screensaver = false, \ .disable_screensaver = false, \

View File

@@ -4,7 +4,9 @@
#include <string.h> #include <string.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include "events.h"
#include "icon.xpm" #include "icon.xpm"
#include "scrcpy.h"
#include "tiny_xpm.h" #include "tiny_xpm.h"
#include "video_buffer.h" #include "video_buffer.h"
#include "util/log.h" #include "util/log.h"
@@ -190,8 +192,36 @@ screen_update_content_rect(struct screen *screen) {
} }
void void
screen_init(struct screen *screen) { screen_init(struct screen *screen, struct video_buffer *vb) {
*screen = (struct screen) SCREEN_INITIALIZER; *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 bool
@@ -199,7 +229,7 @@ screen_init_rendering(struct screen *screen, const char *window_title,
struct size frame_size, bool always_on_top, struct size frame_size, bool always_on_top,
int16_t window_x, int16_t window_y, uint16_t window_width, int16_t window_x, int16_t window_y, uint16_t window_width,
uint16_t window_height, bool window_borderless, uint16_t window_height, bool window_borderless,
uint8_t rotation, enum sc_scale_filter scale_filter) { uint8_t rotation, bool mipmaps) {
screen->frame_size = frame_size; screen->frame_size = frame_size;
screen->rotation = rotation; screen->rotation = rotation;
if (rotation) { if (rotation) {
@@ -246,13 +276,35 @@ screen_init_rendering(struct screen *screen, const char *window_title,
return false; return false;
} }
bool ok = sc_frame_texture_init(&screen->ftex, screen->renderer, SDL_RendererInfo renderer_info;
scale_filter, frame_size); int r = SDL_GetRendererInfo(screen->renderer, &renderer_info);
if (!ok) { const char *renderer_name = r ? NULL : renderer_info.name;
LOGC("Could not init frame texture"); LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)");
SDL_DestroyRenderer(screen->renderer);
SDL_DestroyWindow(screen->window); // starts with "opengl"
return false; bool use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
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); 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"); 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 // Reset the window size to trigger a SIZE_CHANGED event, to workaround
// HiDPI issues with some SDL renderers when several displays having // HiDPI issues with some SDL renderers when several displays having
// different HiDPI scaling are connected // different HiDPI scaling are connected
@@ -280,7 +343,9 @@ screen_show_window(struct screen *screen) {
void void
screen_destroy(struct screen *screen) { screen_destroy(struct screen *screen) {
sc_frame_texture_destroy(&screen->ftex); if (screen->texture) {
SDL_DestroyTexture(screen->texture);
}
SDL_DestroyRenderer(screen->renderer); SDL_DestroyRenderer(screen->renderer);
SDL_DestroyWindow(screen->window); 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 // 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) { prepare_for_frame(struct screen *screen, struct size new_frame_size) {
if (screen->frame_size.width != new_frame_size.width if (screen->frame_size.width != new_frame_size.width
|| screen->frame_size.height != new_frame_size.height) { || screen->frame_size.height != new_frame_size.height) {
// frame dimension changed, destroy texture
SDL_DestroyTexture(screen->texture);
screen->frame_size = new_frame_size; screen->frame_size = new_frame_size;
struct size new_content_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); set_content_size(screen, new_content_size);
screen_update_content_rect(screen); 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 static bool
screen_update_frame(struct screen *screen, struct video_buffer *vb) { screen_update_frame(struct screen *screen) {
const AVFrame *frame = video_buffer_take_rendering_frame(vb); const AVFrame *frame = video_buffer_take_rendering_frame(screen->vb);
struct size new_frame_size = {frame->width, frame->height}; struct size new_frame_size = {frame->width, frame->height};
prepare_for_frame(screen, new_frame_size); if (!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) {
return false; return false;
} }
update_texture(screen, frame);
screen_render(screen, false); screen_render(screen, false);
return true; return true;
@@ -377,18 +467,11 @@ void
screen_render(struct screen *screen, bool update_content_rect) { screen_render(struct screen *screen, bool update_content_rect) {
if (update_content_rect) { if (update_content_rect) {
screen_update_content_rect(screen); 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(screen->renderer);
SDL_RenderClear(ftex->renderer);
if (screen->rotation == 0) { if (screen->rotation == 0) {
SDL_RenderCopy(screen->renderer, ftex->texture, NULL, SDL_RenderCopy(screen->renderer, screen->texture, NULL, &screen->rect);
&screen->rect);
} else { } else {
// rotation in RenderCopyEx() is clockwise, while screen->rotation is // rotation in RenderCopyEx() is clockwise, while screen->rotation is
// counterclockwise (to be consistent with --lock-video-orientation) // counterclockwise (to be consistent with --lock-video-orientation)
@@ -408,10 +491,10 @@ screen_render(struct screen *screen, bool update_content_rect) {
dstrect = &screen->rect; dstrect = &screen->rect;
} }
SDL_RenderCopyEx(screen->renderer, ftex->texture, NULL, dstrect, SDL_RenderCopyEx(screen->renderer, screen->texture, NULL, dstrect,
angle, NULL, 0); angle, NULL, 0);
} }
SDL_RenderPresent(ftex->renderer); SDL_RenderPresent(screen->renderer);
} }
void void
@@ -461,10 +544,26 @@ screen_resize_to_pixel_perfect(struct screen *screen) {
content_size.height); content_size.height);
} }
void bool
screen_handle_window_event(struct screen *screen, screen_handle_event(struct screen *screen, SDL_Event *event) {
const SDL_WindowEvent *event) { switch (event->type) {
switch (event->event) { 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);
}
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: case SDL_WINDOWEVENT_EXPOSED:
screen_render(screen, true); screen_render(screen, true);
break; break;
@@ -476,16 +575,21 @@ screen_handle_window_event(struct screen *screen,
break; break;
case SDL_WINDOWEVENT_RESTORED: case SDL_WINDOWEVENT_RESTORED:
if (screen->fullscreen) { if (screen->fullscreen) {
// On Windows, in maximized+fullscreen, disabling fullscreen // On Windows, in maximized+fullscreen, disabling
// mode unexpectedly triggers the "restored" then "maximized" // fullscreen mode unexpectedly triggers the "restored"
// events, leaving the window in a weird state (maximized // then "maximized" events, leaving the window in a
// according to the events, but not maximized visually). // weird state (maximized according to the events, but
// not maximized visually).
break; break;
} }
screen->maximized = false; screen->maximized = false;
apply_pending_resize(screen); apply_pending_resize(screen);
break; break;
} }
return true;
}
return false;
} }
struct point struct point

View File

@@ -8,17 +8,16 @@
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include "coords.h" #include "coords.h"
#include "frame_texture.h"
#include "opengl.h" #include "opengl.h"
#include "scrcpy.h"
struct video_buffer; struct video_buffer;
struct screen { struct screen {
struct video_buffer *vb;
SDL_Window *window; SDL_Window *window;
SDL_Renderer *renderer; SDL_Renderer *renderer;
struct sc_frame_texture ftex; SDL_Texture *texture;
struct sc_opengl gl;
struct size frame_size; struct size frame_size;
struct size content_size; // rotated frame_size struct size content_size; // rotated frame_size
@@ -35,12 +34,15 @@ struct screen {
bool fullscreen; bool fullscreen;
bool maximized; bool maximized;
bool no_window; bool no_window;
bool mipmaps;
}; };
#define SCREEN_INITIALIZER { \ #define SCREEN_INITIALIZER { \
.vb = NULL, \
.window = NULL, \ .window = NULL, \
.renderer = NULL, \ .renderer = NULL, \
.ftex = {0}, \ .texture = NULL, \
.gl = {0}, \
.frame_size = { \ .frame_size = { \
.width = 0, \ .width = 0, \
.height = 0, \ .height = 0, \
@@ -65,11 +67,12 @@ struct screen {
.fullscreen = false, \ .fullscreen = false, \
.maximized = false, \ .maximized = false, \
.no_window = false, \ .no_window = false, \
.mipmaps = false, \
} }
// initialize default values // initialize default values
void 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) // initialize screen, create window, renderer and texture (window is hidden)
// window_x and window_y accept SC_WINDOW_POSITION_UNDEFINED // window_x and window_y accept SC_WINDOW_POSITION_UNDEFINED
@@ -78,7 +81,7 @@ screen_init_rendering(struct screen *screen, const char *window_title,
struct size frame_size, bool always_on_top, struct size frame_size, bool always_on_top,
int16_t window_x, int16_t window_y, uint16_t window_width, int16_t window_x, int16_t window_y, uint16_t window_width,
uint16_t window_height, bool window_borderless, uint16_t window_height, bool window_borderless,
uint8_t rotation, enum sc_scale_filter scale_filter); uint8_t rotation, bool mipmaps);
// show the window // show the window
void void
@@ -88,10 +91,6 @@ screen_show_window(struct screen *screen);
void void
screen_destroy(struct screen *screen); 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 // render the texture to the renderer
// //
// Set the update_content_rect flag if the window or content size may have // Set the update_content_rect flag if the window or content size may have
@@ -115,9 +114,9 @@ screen_resize_to_pixel_perfect(struct screen *screen);
void void
screen_set_rotation(struct screen *screen, unsigned rotation); screen_set_rotation(struct screen *screen, unsigned rotation);
// react to window events // react to SDL events
void bool
screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *event); screen_handle_event(struct screen *screen, SDL_Event *event);
// convert point from window coordinates to frame coordinates // convert point from window coordinates to frame coordinates
// x and y are expressed in pixels // x and y are expressed in pixels

View File

@@ -375,8 +375,6 @@ server_init(struct server *server) {
server->video_socket = INVALID_SOCKET; server->video_socket = INVALID_SOCKET;
server->control_socket = INVALID_SOCKET; server->control_socket = INVALID_SOCKET;
server->port_range.first = 0;
server->port_range.last = 0;
server->local_port = 0; server->local_port = 0;
server->tunnel_enabled = false; server->tunnel_enabled = false;
@@ -410,8 +408,6 @@ run_wait_server(void *data) {
bool bool
server_start(struct server *server, const char *serial, server_start(struct server *server, const char *serial,
const struct server_params *params) { const struct server_params *params) {
server->port_range = params->port_range;
if (serial) { if (serial) {
server->serial = strdup(serial); server->serial = strdup(serial);
if (!server->serial) { if (!server->serial) {

View File

@@ -26,7 +26,6 @@ struct server {
socket_t server_socket; // only used if !tunnel_forward socket_t server_socket; // only used if !tunnel_forward
socket_t video_socket; socket_t video_socket;
socket_t control_socket; socket_t control_socket;
struct sc_port_range port_range;
uint16_t local_port; // selected from port_range uint16_t local_port; // selected from port_range
bool tunnel_enabled; bool tunnel_enabled;
bool tunnel_forward; // use "adb forward" instead of "adb reverse" bool tunnel_forward; // use "adb forward" instead of "adb reverse"

View File

@@ -4,6 +4,7 @@ project('scrcpy', 'c',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',
'warning_level=2', 'warning_level=2',
'b_ndebug=if-release',
]) ])
if get_option('compile_app') if get_option('compile_app')

View File

@@ -7,6 +7,7 @@ import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaCodecList; import android.media.MediaCodecList;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.view.Surface; import android.view.Surface;
@@ -225,7 +226,9 @@ public class ScreenEncoder implements Device.RotationListener {
} }
private static IBinder createDisplay() { private static IBinder createDisplay() {
return SurfaceControl.createDisplay("scrcpy", true); // Since Android 12, secure displays could not be created with shell permissions anymore
boolean secure = Build.VERSION.SDK_INT <= Build.VERSION_CODES.R;
return SurfaceControl.createDisplay("scrcpy", secure);
} }
private static void configure(MediaCodec codec, MediaFormat format) { private static void configure(MediaCodec codec, MediaFormat format) {