mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-02-27 16:54:31 +01:00
Compare commits
8 Commits
pause-if-e
...
early-wind
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13039e8db5 | ||
|
|
f2de2c88ff | ||
|
|
2e9175a4ea | ||
|
|
e78281c864 | ||
|
|
10e0c3226c | ||
|
|
323549e82f | ||
|
|
90d11810e3 | ||
|
|
1f19ec4aec |
@@ -9,6 +9,7 @@
|
||||
|
||||
enum {
|
||||
SC_EVENT_NEW_FRAME = SDL_EVENT_USER,
|
||||
SC_EVENT_OPEN_WINDOW,
|
||||
SC_EVENT_RUN_ON_MAIN_THREAD,
|
||||
SC_EVENT_DEVICE_DISCONNECTED,
|
||||
SC_EVENT_SERVER_CONNECTION_FAILED,
|
||||
|
||||
@@ -198,19 +198,30 @@ sc_screen_update_content_rect(struct sc_screen *screen) {
|
||||
// changed, so that the content rectangle is recomputed
|
||||
static void
|
||||
sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
||||
assert(!screen->video || screen->has_video_window);
|
||||
assert(screen->window_shown);
|
||||
|
||||
if (update_content_rect) {
|
||||
sc_screen_update_content_rect(screen);
|
||||
}
|
||||
|
||||
SDL_Renderer *renderer = screen->renderer;
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||
sc_sdl_render_clear(renderer);
|
||||
|
||||
bool ok = false;
|
||||
SDL_Texture *texture = screen->tex.texture;
|
||||
if (!texture) {
|
||||
LOGW("No texture to render");
|
||||
// Draw a dark 10x10 square in the top-right corner to distinguish a
|
||||
// black frame from the absence of a frame
|
||||
struct sc_size render_size = sc_sdl_get_render_output_size(renderer);
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0x33, 0xff);
|
||||
SDL_FRect rect = {
|
||||
.x = render_size.width - 20,
|
||||
.y = 10,
|
||||
.w = 10,
|
||||
.h = 10,
|
||||
};
|
||||
SDL_RenderFillRect(renderer, &rect);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -280,11 +291,8 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink,
|
||||
const AVCodecContext *ctx,
|
||||
const struct sc_stream_session *session) {
|
||||
assert(ctx->pix_fmt == AV_PIX_FMT_YUV420P);
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
|
||||
struct sc_screen *screen = DOWNCAST(sink);
|
||||
(void) screen;
|
||||
|
||||
if (ctx->width <= 0 || ctx->width > 0xFFFF
|
||||
|| ctx->height <= 0 || ctx->height > 0xFFFF) {
|
||||
@@ -292,6 +300,19 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink,
|
||||
return false;
|
||||
}
|
||||
|
||||
// content_size can be written from this thread, because it is never read
|
||||
// from the main thread before handling SC_EVENT_OPEN_WINDOW (which acts as
|
||||
// a synchronization point) when video is enabled
|
||||
screen->frame_size.width = session->video.width;
|
||||
screen->frame_size.height = session->video.height;
|
||||
screen->content_size = get_oriented_size(screen->frame_size,
|
||||
screen->orientation);
|
||||
|
||||
bool ok = sc_push_event(SC_EVENT_OPEN_WINDOW);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
screen->open = true;
|
||||
#endif
|
||||
@@ -341,8 +362,7 @@ bool
|
||||
sc_screen_init(struct sc_screen *screen,
|
||||
const struct sc_screen_params *params) {
|
||||
screen->resize_pending = false;
|
||||
screen->has_frame = false;
|
||||
screen->has_video_window = false;
|
||||
screen->window_shown = false;
|
||||
screen->paused = false;
|
||||
screen->resume_frame = NULL;
|
||||
screen->orientation = SC_ORIENTATION_0;
|
||||
@@ -533,6 +553,7 @@ sc_screen_init(struct sc_screen *screen,
|
||||
|
||||
if (!screen->video) {
|
||||
// Show the window immediately
|
||||
screen->window_shown = true;
|
||||
sc_sdl_show_window(screen->window);
|
||||
|
||||
if (sc_screen_is_relative_mode(screen)) {
|
||||
@@ -589,6 +610,7 @@ sc_screen_show_initial_window(struct sc_screen *screen) {
|
||||
sc_fps_counter_start(&screen->fps_counter);
|
||||
}
|
||||
|
||||
screen->window_shown = true;
|
||||
sc_sdl_show_window(screen->window);
|
||||
sc_screen_update_content_rect(screen);
|
||||
}
|
||||
@@ -596,6 +618,7 @@ sc_screen_show_initial_window(struct sc_screen *screen) {
|
||||
void
|
||||
sc_screen_hide_window(struct sc_screen *screen) {
|
||||
sc_sdl_hide_window(screen->window);
|
||||
screen->window_shown = false;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -692,14 +715,14 @@ sc_screen_set_orientation(struct sc_screen *screen,
|
||||
static bool
|
||||
sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
assert(screen->window_shown);
|
||||
|
||||
sc_fps_counter_add_rendered_frame(&screen->fps_counter);
|
||||
|
||||
AVFrame *frame = screen->frame;
|
||||
struct sc_size new_frame_size = {frame->width, frame->height};
|
||||
|
||||
if (!screen->has_frame
|
||||
|| 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) {
|
||||
|
||||
// frame dimension changed
|
||||
@@ -707,14 +730,8 @@ sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
|
||||
struct sc_size new_content_size =
|
||||
get_oriented_size(new_frame_size, screen->orientation);
|
||||
if (screen->has_frame) {
|
||||
set_content_size(screen, new_content_size);
|
||||
sc_screen_update_content_rect(screen);
|
||||
} else {
|
||||
// This is the first frame
|
||||
screen->has_frame = true;
|
||||
screen->content_size = new_content_size;
|
||||
}
|
||||
set_content_size(screen, new_content_size);
|
||||
sc_screen_update_content_rect(screen);
|
||||
}
|
||||
|
||||
bool ok = sc_texture_set_from_frame(&screen->tex, frame);
|
||||
@@ -722,18 +739,6 @@ sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(screen->has_frame);
|
||||
if (!screen->has_video_window) {
|
||||
screen->has_video_window = true;
|
||||
// this is the very first frame, show the window
|
||||
sc_screen_show_initial_window(screen);
|
||||
|
||||
if (sc_screen_is_relative_mode(screen)) {
|
||||
// Capture mouse on start
|
||||
sc_mouse_capture_set_active(&screen->mc, true);
|
||||
}
|
||||
}
|
||||
|
||||
sc_screen_render(screen, false);
|
||||
return true;
|
||||
}
|
||||
@@ -854,9 +859,17 @@ sc_screen_resize_to_pixel_perfect(struct sc_screen *screen) {
|
||||
|
||||
void
|
||||
sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
||||
// !video implies !has_video_window
|
||||
assert(screen->video || !screen->has_video_window);
|
||||
switch (event->type) {
|
||||
case SC_EVENT_OPEN_WINDOW:
|
||||
sc_screen_show_initial_window(screen);
|
||||
|
||||
if (sc_screen_is_relative_mode(screen)) {
|
||||
// Capture mouse on start
|
||||
sc_mouse_capture_set_active(&screen->mc, true);
|
||||
}
|
||||
|
||||
sc_screen_render(screen, false);
|
||||
return;
|
||||
case SC_EVENT_NEW_FRAME: {
|
||||
bool ok = sc_screen_update_frame(screen);
|
||||
if (!ok) {
|
||||
@@ -865,28 +878,27 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
||||
return;
|
||||
}
|
||||
case SDL_EVENT_WINDOW_EXPOSED:
|
||||
if (!screen->video || screen->has_video_window) {
|
||||
sc_screen_render(screen, true);
|
||||
}
|
||||
sc_screen_render(screen, true);
|
||||
return;
|
||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||
if (screen->has_video_window) {
|
||||
// This event can be triggered before the window is shown
|
||||
if (screen->window_shown) {
|
||||
sc_screen_render(screen, true);
|
||||
}
|
||||
return;
|
||||
case SDL_EVENT_WINDOW_RESTORED:
|
||||
if (screen->has_video_window && is_windowed(screen)) {
|
||||
if (screen->video && is_windowed(screen)) {
|
||||
apply_pending_resize(screen);
|
||||
sc_screen_render(screen, true);
|
||||
}
|
||||
return;
|
||||
case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
|
||||
LOGD("Switched to fullscreen mode");
|
||||
assert(screen->has_video_window);
|
||||
assert(screen->video);
|
||||
return;
|
||||
case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
|
||||
LOGD("Switched to windowed mode");
|
||||
assert(screen->has_video_window);
|
||||
assert(screen->video);
|
||||
if (is_windowed(screen)) {
|
||||
apply_pending_resize(screen);
|
||||
sc_screen_render(screen, true);
|
||||
|
||||
@@ -70,8 +70,7 @@ struct sc_screen {
|
||||
enum sc_orientation orientation;
|
||||
// rectangle of the content (excluding black borders)
|
||||
struct SDL_FRect rect;
|
||||
bool has_frame;
|
||||
bool has_video_window;
|
||||
bool window_shown;
|
||||
|
||||
AVFrame *frame;
|
||||
|
||||
|
||||
@@ -93,4 +93,4 @@ Then just double-click on that file to run it.
|
||||
|
||||
To start scrcpy without opening a terminal, double-click `scrcpy-noconsole.vbs`
|
||||
(note that errors won't be shown). To pass arguments, edit (a copy of)
|
||||
`scrcpy-noconsole.vbs` add and the desired arguments.
|
||||
`scrcpy-noconsole.vbs` and add the desired arguments.
|
||||
|
||||
@@ -22,9 +22,12 @@ app/deps/libusb.sh linux native static
|
||||
DEPS_INSTALL_DIR="$PWD/app/deps/work/install/linux-native-static"
|
||||
ADB_INSTALL_DIR="$PWD/app/deps/work/install/adb-linux"
|
||||
|
||||
# Never fall back to system libs
|
||||
unset PKG_CONFIG_PATH
|
||||
export PKG_CONFIG_LIBDIR="$DEPS_INSTALL_DIR/lib/pkgconfig"
|
||||
|
||||
rm -rf "$LINUX_BUILD_DIR"
|
||||
meson setup "$LINUX_BUILD_DIR" \
|
||||
--pkg-config-path="$DEPS_INSTALL_DIR/lib/pkgconfig" \
|
||||
-Dc_args="-I$DEPS_INSTALL_DIR/include" \
|
||||
-Dc_link_args="-L$DEPS_INSTALL_DIR/lib" \
|
||||
--buildtype=release \
|
||||
|
||||
@@ -22,9 +22,12 @@ app/deps/libusb.sh macos native static
|
||||
DEPS_INSTALL_DIR="$PWD/app/deps/work/install/macos-native-static"
|
||||
ADB_INSTALL_DIR="$PWD/app/deps/work/install/adb-macos"
|
||||
|
||||
# Never fall back to system libs
|
||||
unset PKG_CONFIG_PATH
|
||||
export PKG_CONFIG_LIBDIR="$DEPS_INSTALL_DIR/lib/pkgconfig"
|
||||
|
||||
rm -rf "$MACOS_BUILD_DIR"
|
||||
meson setup "$MACOS_BUILD_DIR" \
|
||||
--pkg-config-path="$DEPS_INSTALL_DIR/lib/pkgconfig" \
|
||||
-Dc_args="-I$DEPS_INSTALL_DIR/include" \
|
||||
-Dc_link_args="-L$DEPS_INSTALL_DIR/lib" \
|
||||
--buildtype=release \
|
||||
|
||||
@@ -29,9 +29,12 @@ app/deps/libusb.sh $WINXX cross shared
|
||||
DEPS_INSTALL_DIR="$PWD/app/deps/work/install/$WINXX-cross-shared"
|
||||
ADB_INSTALL_DIR="$PWD/app/deps/work/install/adb-windows"
|
||||
|
||||
# Never fall back to system libs
|
||||
unset PKG_CONFIG_PATH
|
||||
export PKG_CONFIG_LIBDIR="$DEPS_INSTALL_DIR/lib/pkgconfig"
|
||||
|
||||
rm -rf "$WINXX_BUILD_DIR"
|
||||
meson setup "$WINXX_BUILD_DIR" \
|
||||
--pkg-config-path="$DEPS_INSTALL_DIR/lib/pkgconfig" \
|
||||
-Dc_args="-I$DEPS_INSTALL_DIR/include" \
|
||||
-Dc_link_args="-L$DEPS_INSTALL_DIR/lib" \
|
||||
--cross-file=cross_$WINXX.txt \
|
||||
|
||||
@@ -264,6 +264,10 @@ public class SurfaceEncoder implements AsyncProcessor {
|
||||
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL);
|
||||
// display the very first frame, and recover from bad quality when no new frames
|
||||
format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, REPEAT_FRAME_DELAY_US); // µs
|
||||
// real-time priority
|
||||
format.setInteger(MediaFormat.KEY_PRIORITY, 0);
|
||||
// output 1 frame as soon as 1 frame is queued
|
||||
format.setInteger(MediaFormat.KEY_LATENCY, 1);
|
||||
if (maxFps > 0) {
|
||||
// The key existed privately before Android 10:
|
||||
// <https://android.googlesource.com/platform/frameworks/base/+/625f0aad9f7a259b6881006ad8710adce57d1384%5E%21/>
|
||||
|
||||
Reference in New Issue
Block a user