From 7d10ec2b5aab648dd06b5ea9770f7cedacfbd74d Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Tue, 26 Feb 2019 20:35:37 +0100 Subject: [PATCH 01/24] Add shortcut to expand/collapse notification panel Use Ctrl+n to expand, Ctrl+Shift+n to collapse. Fixes --- README.md | 2 + app/src/control_event.h | 8 ++- app/src/input_manager.c | 69 +++++++++++++------ app/src/main.c | 6 ++ .../com/genymobile/scrcpy/ControlEvent.java | 2 + .../java/com/genymobile/scrcpy/Device.java | 8 +++ .../genymobile/scrcpy/EventController.java | 7 ++ .../scrcpy/wrappers/ServiceManager.java | 8 +++ .../scrcpy/wrappers/StatusBarManager.java | 41 +++++++++++ 9 files changed, 129 insertions(+), 22 deletions(-) create mode 100644 server/src/main/java/com/genymobile/scrcpy/wrappers/StatusBarManager.java diff --git a/README.md b/README.md index 1fdb2c83..af67a17b 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,8 @@ you are interested, see [issue 14]. | click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ (`Cmd`+`↓` on MacOS) | | click on `POWER` | `Ctrl`+`p` | | turn screen on | _Right-click²_ | + | expand notification panel | `Ctrl`+`n` | + | collapse notification panel | `Ctrl`+`Shift`+`n` | | paste computer clipboard to device | `Ctrl`+`v` | | enable/disable FPS counter (on stdout) | `Ctrl`+`i` | diff --git a/app/src/control_event.h b/app/src/control_event.h index 471a9a9b..c2569615 100644 --- a/app/src/control_event.h +++ b/app/src/control_event.h @@ -20,7 +20,11 @@ enum control_event_type { CONTROL_EVENT_TYPE_COMMAND, }; -#define CONTROL_EVENT_COMMAND_BACK_OR_SCREEN_ON 0 +enum control_event_command { + CONTROL_EVENT_COMMAND_BACK_OR_SCREEN_ON, + CONTROL_EVENT_COMMAND_EXPAND_NOTIFICATION_PANEL, + CONTROL_EVENT_COMMAND_COLLAPSE_NOTIFICATION_PANEL, +}; struct control_event { enum control_event_type type; @@ -44,7 +48,7 @@ struct control_event { Sint32 vscroll; } scroll_event; struct { - int action; + enum control_event_command action; } command_event; }; }; diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 7099249e..ef3d372c 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -94,6 +94,26 @@ static void press_back_or_turn_screen_on(struct controller *controller) { } } +static void expand_notification_panel(struct controller *controller) { + struct control_event control_event; + control_event.type = CONTROL_EVENT_TYPE_COMMAND; + control_event.command_event.action = CONTROL_EVENT_COMMAND_EXPAND_NOTIFICATION_PANEL; + + if (!controller_push_event(controller, &control_event)) { + LOGW("Cannot expand notification panel"); + } +} + +static void collapse_notification_panel(struct controller *controller) { + struct control_event control_event; + control_event.type = CONTROL_EVENT_TYPE_COMMAND; + control_event.command_event.action = CONTROL_EVENT_COMMAND_COLLAPSE_NOTIFICATION_PANEL; + + if (!controller_push_event(controller, &control_event)) { + LOGW("Cannot collapse notification panel"); + } +} + static void switch_fps_counter_state(struct frames *frames) { mutex_lock(frames->mutex); if (frames->fps_counter.started) { @@ -162,47 +182,42 @@ void input_manager_process_key(struct input_manager *input_manager, // capture all Ctrl events if (ctrl | meta) { - SDL_bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT); - if (shift) { - // currently, there is no shortcut involving SHIFT - return; - } - SDL_Keycode keycode = event->keysym.sym; int action = event->type == SDL_KEYDOWN ? ACTION_DOWN : ACTION_UP; SDL_bool repeat = event->repeat; + SDL_bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT); switch (keycode) { case SDLK_h: - if (ctrl && !meta && !repeat) { + if (ctrl && !meta && !shift && !repeat) { action_home(input_manager->controller, action); } return; case SDLK_b: // fall-through case SDLK_BACKSPACE: - if (ctrl && !meta && !repeat) { + if (ctrl && !meta && !shift && !repeat) { action_back(input_manager->controller, action); } return; case SDLK_s: - if (ctrl && !meta && !repeat) { + if (ctrl && !meta && !shift && !repeat) { action_app_switch(input_manager->controller, action); } return; case SDLK_m: - if (ctrl && !meta && !repeat) { + if (ctrl && !meta && !shift && !repeat) { action_menu(input_manager->controller, action); } return; case SDLK_p: - if (ctrl && !meta && !repeat) { + if (ctrl && !meta && !shift && !repeat) { action_power(input_manager->controller, action); } return; case SDLK_DOWN: #ifdef __APPLE__ - if (!ctrl && meta) { + if (!ctrl && meta && !shift) { #else - if (ctrl && !meta) { + if (ctrl && !meta && !shift) { #endif // forward repeated events action_volume_down(input_manager->controller, action); @@ -210,39 +225,53 @@ void input_manager_process_key(struct input_manager *input_manager, return; case SDLK_UP: #ifdef __APPLE__ - if (!ctrl && meta) { + if (!ctrl && meta && !shift) { #else - if (ctrl && !meta) { + if (ctrl && !meta && !shift) { #endif // forward repeated events action_volume_up(input_manager->controller, action); } return; case SDLK_v: - if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) { + if (ctrl && !meta && !shift && !repeat + && event->type == SDL_KEYDOWN) { clipboard_paste(input_manager->controller); } return; case SDLK_f: - if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) { + if (ctrl && !meta && !shift && !repeat + && event->type == SDL_KEYDOWN) { screen_switch_fullscreen(input_manager->screen); } return; case SDLK_x: - if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) { + if (ctrl && !meta && !shift && !repeat + && event->type == SDL_KEYDOWN) { screen_resize_to_fit(input_manager->screen); } return; case SDLK_g: - if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) { + if (ctrl && !meta && !shift && !repeat + && event->type == SDL_KEYDOWN) { screen_resize_to_pixel_perfect(input_manager->screen); } return; case SDLK_i: - if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) { + if (ctrl && !meta && !shift && !repeat + && event->type == SDL_KEYDOWN) { switch_fps_counter_state(input_manager->frames); } return; + case SDLK_n: + if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) { + if (shift) { + collapse_notification_panel(input_manager->controller); + } else { + expand_notification_panel(input_manager->controller); + } + } + return; } return; diff --git a/app/src/main.c b/app/src/main.c index 35bb74ea..f18b3aaf 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -120,6 +120,12 @@ static void usage(const char *arg0) { " Right-click (when screen is off)\n" " turn screen on\n" "\n" + " Ctrl+n\n" + " expand notification panel\n" + "\n" + " Ctrl+Shift+n\n" + " collapse notification panel\n" + "\n" " Ctrl+v\n" " paste computer clipboard to device\n" "\n" diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java b/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java index 3c9cbda1..8b0f9e2b 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java @@ -12,6 +12,8 @@ public final class ControlEvent { public static final int TYPE_COMMAND = 4; public static final int COMMAND_BACK_OR_SCREEN_ON = 0; + public static final int COMMAND_EXPAND_NOTIFICATION_PANEL = 1; + public static final int COMMAND_COLLAPSE_NOTIFICATION_PANEL = 2; private int type; private String text; diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java index d2862acb..60122c5a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/Device.java @@ -132,6 +132,14 @@ public final class Device { this.rotationListener = rotationListener; } + public void expandNotificationPanel() { + serviceManager.getStatusBarManager().expandNotificationsPanel(); + } + + public void collapsePanels() { + serviceManager.getStatusBarManager().collapsePanels(); + } + static Rect flipRect(Rect crop) { return new Rect(crop.top, crop.left, crop.bottom, crop.right); } diff --git a/server/src/main/java/com/genymobile/scrcpy/EventController.java b/server/src/main/java/com/genymobile/scrcpy/EventController.java index 547e20ca..5fa2cab2 100644 --- a/server/src/main/java/com/genymobile/scrcpy/EventController.java +++ b/server/src/main/java/com/genymobile/scrcpy/EventController.java @@ -1,6 +1,7 @@ package com.genymobile.scrcpy; import com.genymobile.scrcpy.wrappers.InputManager; +import com.genymobile.scrcpy.wrappers.ServiceManager; import android.graphics.Point; import android.os.SystemClock; @@ -172,6 +173,12 @@ public class EventController { switch (action) { case ControlEvent.COMMAND_BACK_OR_SCREEN_ON: return pressBackOrTurnScreenOn(); + case ControlEvent.COMMAND_EXPAND_NOTIFICATION_PANEL: + device.expandNotificationPanel(); + return true; + case ControlEvent.COMMAND_COLLAPSE_NOTIFICATION_PANEL: + device.collapsePanels(); + return true; default: Ln.w("Unsupported command: " + action); } diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java index 2d98d0a8..3bcdc0e6 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java @@ -14,6 +14,7 @@ public final class ServiceManager { private DisplayManager displayManager; private InputManager inputManager; private PowerManager powerManager; + private StatusBarManager statusBarManager; public ServiceManager() { try { @@ -60,4 +61,11 @@ public final class ServiceManager { } return powerManager; } + + public StatusBarManager getStatusBarManager() { + if (statusBarManager == null) { + statusBarManager = new StatusBarManager(getService("statusbar", "com.android.internal.statusbar.IStatusBarService")); + } + return statusBarManager; + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/StatusBarManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/StatusBarManager.java new file mode 100644 index 00000000..aacd5f1a --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/StatusBarManager.java @@ -0,0 +1,41 @@ +package com.genymobile.scrcpy.wrappers; + +import android.annotation.SuppressLint; +import android.os.IInterface; +import android.view.InputEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class StatusBarManager { + + private final IInterface manager; + private final Method expandNotificationsPanelMethod; + private final Method collapsePanelsMethod; + + public StatusBarManager(IInterface manager) { + this.manager = manager; + try { + expandNotificationsPanelMethod = manager.getClass().getMethod("expandNotificationsPanel"); + collapsePanelsMethod = manager.getClass().getMethod("collapsePanels"); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + public void expandNotificationsPanel() { + try { + expandNotificationsPanelMethod.invoke(manager); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new AssertionError(e); + } + } + + public void collapsePanels() { + try { + collapsePanelsMethod.invoke(manager); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new AssertionError(e); + } + } +} From aacb09a3d66d018a6e1ff2988729d8c6b274755c Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 14:48:34 +0100 Subject: [PATCH 02/24] Remove unused mutex field in decoder --- app/src/decoder.h | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/decoder.h b/app/src/decoder.h index 610de000..f266d9ba 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -18,7 +18,6 @@ struct decoder { struct frames *frames; socket_t video_socket; SDL_Thread *thread; - SDL_mutex *mutex; struct recorder *recorder; struct receiver_state { // meta (in order) for frames not consumed yet From fff87095d95c257f9d6cab34f605da65d0bf478d Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 15:16:55 +0100 Subject: [PATCH 03/24] Rename "frames" to "video_buffer" It better describes the purpose of the structure. --- app/meson.build | 2 +- app/src/decoder.c | 14 ++-- app/src/decoder.h | 6 +- app/src/frames.c | 110 --------------------------- app/src/input_manager.c | 14 ++-- app/src/input_manager.h | 4 +- app/src/scrcpy.c | 18 ++--- app/src/screen.c | 11 +-- app/src/screen.h | 5 +- app/src/video_buffer.c | 110 +++++++++++++++++++++++++++ app/src/{frames.h => video_buffer.h} | 18 ++--- 11 files changed, 157 insertions(+), 155 deletions(-) delete mode 100644 app/src/frames.c create mode 100644 app/src/video_buffer.c rename app/src/{frames.h => video_buffer.h} (65%) diff --git a/app/meson.build b/app/meson.build index 3286fde1..4c4c807b 100644 --- a/app/meson.build +++ b/app/meson.build @@ -8,7 +8,6 @@ src = [ 'src/device.c', 'src/file_handler.c', 'src/fps_counter.c', - 'src/frames.c', 'src/input_manager.c', 'src/lock_util.c', 'src/net.c', @@ -18,6 +17,7 @@ src = [ 'src/server.c', 'src/str_util.c', 'src/tiny_xpm.c', + 'src/video_buffer.c', ] if not get_option('crossbuild_windows') diff --git a/app/src/decoder.c b/app/src/decoder.c index 9b3ca2f1..adc59a30 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -12,10 +12,10 @@ #include "config.h" #include "buffer_util.h" #include "events.h" -#include "frames.h" #include "lock_util.h" #include "log.h" #include "recorder.h" +#include "video_buffer.h" #define BUFSIZE 0x10000 @@ -134,7 +134,7 @@ static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) { // set the decoded frame as ready for rendering, and notify static void push_frame(struct decoder *decoder) { - SDL_bool previous_frame_consumed = frames_offer_decoded_frame(decoder->frames); + SDL_bool previous_frame_consumed = video_buffer_offer_decoded_frame(decoder->video_buffer); if (!previous_frame_consumed) { // the previous EVENT_NEW_FRAME will consume this frame return; @@ -227,7 +227,7 @@ static int run_decoder(void *data) { LOGE("Could not send video packet: %d", ret); goto run_quit; } - ret = avcodec_receive_frame(codec_ctx, decoder->frames->decoding_frame); + ret = avcodec_receive_frame(codec_ctx, decoder->video_buffer->decoding_frame); if (!ret) { // a frame was received push_frame(decoder); @@ -239,7 +239,7 @@ static int run_decoder(void *data) { #else while (packet.size > 0) { int got_picture; - int len = avcodec_decode_video2(codec_ctx, decoder->frames->decoding_frame, &got_picture, &packet); + int len = avcodec_decode_video2(codec_ctx, decoder->video_buffer->decoding_frame, &got_picture, &packet); if (len < 0) { LOGE("Could not decode video packet: %d", len); av_packet_unref(&packet); @@ -298,9 +298,9 @@ run_end: return 0; } -void decoder_init(struct decoder *decoder, struct frames *frames, +void decoder_init(struct decoder *decoder, struct video_buffer *vb, socket_t video_socket, struct recorder *recorder) { - decoder->frames = frames; + decoder->video_buffer = vb; decoder->video_socket = video_socket; decoder->recorder = recorder; } @@ -317,7 +317,7 @@ SDL_bool decoder_start(struct decoder *decoder) { } void decoder_stop(struct decoder *decoder) { - frames_stop(decoder->frames); + video_buffer_stop(decoder->video_buffer); } void decoder_join(struct decoder *decoder) { diff --git a/app/src/decoder.h b/app/src/decoder.h index f266d9ba..240dab00 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -7,7 +7,7 @@ #include "common.h" #include "net.h" -struct frames; +struct video_buffer; struct frame_meta { uint64_t pts; @@ -15,7 +15,7 @@ struct frame_meta { }; struct decoder { - struct frames *frames; + struct video_buffer *video_buffer; socket_t video_socket; SDL_Thread *thread; struct recorder *recorder; @@ -26,7 +26,7 @@ struct decoder { } receiver_state; }; -void decoder_init(struct decoder *decoder, struct frames *frames, +void decoder_init(struct decoder *decoder, struct video_buffer *vb, socket_t video_socket, struct recorder *recoder); SDL_bool decoder_start(struct decoder *decoder); void decoder_stop(struct decoder *decoder); diff --git a/app/src/frames.c b/app/src/frames.c deleted file mode 100644 index 514d4788..00000000 --- a/app/src/frames.c +++ /dev/null @@ -1,110 +0,0 @@ -#include "frames.h" - -#include -#include -#include -#include - -#include "config.h" -#include "lock_util.h" -#include "log.h" - -SDL_bool frames_init(struct frames *frames) { - if (!(frames->decoding_frame = av_frame_alloc())) { - goto error_0; - } - - if (!(frames->rendering_frame = av_frame_alloc())) { - goto error_1; - } - - if (!(frames->mutex = SDL_CreateMutex())) { - goto error_2; - } - -#ifndef SKIP_FRAMES - if (!(frames->rendering_frame_consumed_cond = SDL_CreateCond())) { - SDL_DestroyMutex(frames->mutex); - goto error_2; - } - frames->stopped = SDL_FALSE; -#endif - - // there is initially no rendering frame, so consider it has already been - // consumed - frames->rendering_frame_consumed = SDL_TRUE; - fps_counter_init(&frames->fps_counter); - - return SDL_TRUE; - -error_2: - av_frame_free(&frames->rendering_frame); -error_1: - av_frame_free(&frames->decoding_frame); -error_0: - return SDL_FALSE; -} - -void frames_destroy(struct frames *frames) { -#ifndef SKIP_FRAMES - SDL_DestroyCond(frames->rendering_frame_consumed_cond); -#endif - SDL_DestroyMutex(frames->mutex); - av_frame_free(&frames->rendering_frame); - av_frame_free(&frames->decoding_frame); -} - -static void frames_swap(struct frames *frames) { - AVFrame *tmp = frames->decoding_frame; - frames->decoding_frame = frames->rendering_frame; - frames->rendering_frame = tmp; -} - -SDL_bool frames_offer_decoded_frame(struct frames *frames) { - mutex_lock(frames->mutex); -#ifndef SKIP_FRAMES - // if SKIP_FRAMES is disabled, then the decoder must wait for the current - // frame to be consumed - while (!frames->rendering_frame_consumed && !frames->stopped) { - cond_wait(frames->rendering_frame_consumed_cond, frames->mutex); - } -#else - if (frames->fps_counter.started && !frames->rendering_frame_consumed) { - fps_counter_add_skipped_frame(&frames->fps_counter); - } -#endif - - frames_swap(frames); - - SDL_bool previous_frame_consumed = frames->rendering_frame_consumed; - frames->rendering_frame_consumed = SDL_FALSE; - - mutex_unlock(frames->mutex); - return previous_frame_consumed; -} - -const AVFrame *frames_consume_rendered_frame(struct frames *frames) { - SDL_assert(!frames->rendering_frame_consumed); - frames->rendering_frame_consumed = SDL_TRUE; - if (frames->fps_counter.started) { - fps_counter_add_rendered_frame(&frames->fps_counter); - } -#ifndef SKIP_FRAMES - // if SKIP_FRAMES is disabled, then notify the decoder the current frame is - // consumed, so that it may push a new one - cond_signal(frames->rendering_frame_consumed_cond); -#endif - return frames->rendering_frame; -} - -void frames_stop(struct frames *frames) { -#ifdef SKIP_FRAMES - (void) frames; // unused -#else - mutex_lock(frames->mutex); - frames->stopped = SDL_TRUE; - mutex_unlock(frames->mutex); - // wake up blocking wait - cond_signal(frames->rendering_frame_consumed_cond); -#endif -} diff --git a/app/src/input_manager.c b/app/src/input_manager.c index ef3d372c..35e029f0 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -114,16 +114,16 @@ static void collapse_notification_panel(struct controller *controller) { } } -static void switch_fps_counter_state(struct frames *frames) { - mutex_lock(frames->mutex); - if (frames->fps_counter.started) { +static void switch_fps_counter_state(struct video_buffer *vb) { + mutex_lock(vb->mutex); + if (vb->fps_counter.started) { LOGI("FPS counter stopped"); - fps_counter_stop(&frames->fps_counter); + fps_counter_stop(&vb->fps_counter); } else { LOGI("FPS counter started"); - fps_counter_start(&frames->fps_counter); + fps_counter_start(&vb->fps_counter); } - mutex_unlock(frames->mutex); + mutex_unlock(vb->mutex); } static void clipboard_paste(struct controller *controller) { @@ -260,7 +260,7 @@ void input_manager_process_key(struct input_manager *input_manager, case SDLK_i: if (ctrl && !meta && !shift && !repeat && event->type == SDL_KEYDOWN) { - switch_fps_counter_state(input_manager->frames); + switch_fps_counter_state(input_manager->video_buffer); } return; case SDLK_n: diff --git a/app/src/input_manager.h b/app/src/input_manager.h index b9037aa1..7aed1793 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -4,12 +4,12 @@ #include "common.h" #include "controller.h" #include "fps_counter.h" -#include "frames.h" +#include "video_buffer.h" #include "screen.h" struct input_manager { struct controller *controller; - struct frames *frames; + struct video_buffer *video_buffer; struct screen *screen; }; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 9a1c29d5..fa347bf5 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -14,7 +14,6 @@ #include "device.h" #include "events.h" #include "file_handler.h" -#include "frames.h" #include "fps_counter.h" #include "input_manager.h" #include "log.h" @@ -24,10 +23,11 @@ #include "screen.h" #include "server.h" #include "tiny_xpm.h" +#include "video_buffer.h" static struct server server = SERVER_INITIALIZER; static struct screen screen = SCREEN_INITIALIZER; -static struct frames frames; +static struct video_buffer video_buffer; static struct decoder decoder; static struct controller controller; static struct file_handler file_handler; @@ -35,7 +35,7 @@ static struct recorder recorder; static struct input_manager input_manager = { .controller = &controller, - .frames = &frames, + .video_buffer = &video_buffer, .screen = &screen, }; @@ -82,7 +82,7 @@ static SDL_bool event_loop(void) { // this is the very first frame, show the window screen_show_window(&screen); } - if (!screen_update_frame(&screen, &frames)) { + if (!screen_update_frame(&screen, &video_buffer)) { return SDL_FALSE; } break; @@ -215,7 +215,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { goto finally_destroy_server; } - if (!frames_init(&frames)) { + if (!video_buffer_init(&video_buffer)) { server_stop(&server); ret = SDL_FALSE; goto finally_destroy_server; @@ -224,7 +224,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { if (!file_handler_init(&file_handler, server.serial)) { ret = SDL_FALSE; server_stop(&server); - goto finally_destroy_frames; + goto finally_destroy_video_buffer; } struct recorder *rec = NULL; @@ -242,7 +242,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { av_log_set_callback(av_log_callback); - decoder_init(&decoder, &frames, device_socket, rec); + decoder_init(&decoder, &video_buffer, device_socket, rec); // now we consumed the header values, the socket receives the video stream // start the decoder @@ -299,8 +299,8 @@ finally_destroy_recorder: if (options->record_filename) { recorder_destroy(&recorder); } -finally_destroy_frames: - frames_destroy(&frames); +finally_destroy_video_buffer: + video_buffer_destroy(&video_buffer); finally_destroy_server: if (options->show_touches) { if (!show_touches_waited) { diff --git a/app/src/screen.c b/app/src/screen.c index 1632e27f..54920c94 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -8,6 +8,7 @@ #include "lock_util.h" #include "log.h" #include "tiny_xpm.h" +#include "video_buffer.h" #define DISPLAY_MARGINS 96 @@ -262,16 +263,16 @@ static void update_texture(struct screen *screen, const AVFrame *frame) { frame->data[2], frame->linesize[2]); } -SDL_bool screen_update_frame(struct screen *screen, struct frames *frames) { - mutex_lock(frames->mutex); - const AVFrame *frame = frames_consume_rendered_frame(frames); +SDL_bool screen_update_frame(struct screen *screen, struct video_buffer *vb) { + mutex_lock(vb->mutex); + const AVFrame *frame = video_buffer_consume_rendered_frame(vb); struct size new_frame_size = {frame->width, frame->height}; if (!prepare_for_frame(screen, new_frame_size)) { - mutex_unlock(frames->mutex); + mutex_unlock(vb->mutex); return SDL_FALSE; } update_texture(screen, frame); - mutex_unlock(frames->mutex); + mutex_unlock(vb->mutex); screen_render(screen); return SDL_TRUE; diff --git a/app/src/screen.h b/app/src/screen.h index 05729a12..4a13bfca 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -5,7 +5,8 @@ #include #include "common.h" -#include "frames.h" + +struct video_buffer; struct screen { SDL_Window *window; @@ -53,7 +54,7 @@ void screen_show_window(struct screen *screen); void screen_destroy(struct screen *screen); // resize if necessary and write the rendered frame into the texture -SDL_bool screen_update_frame(struct screen *screen, struct frames *frames); +SDL_bool screen_update_frame(struct screen *screen, struct video_buffer *vb); // render the texture to the renderer void screen_render(struct screen *screen); diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c new file mode 100644 index 00000000..f2a288d4 --- /dev/null +++ b/app/src/video_buffer.c @@ -0,0 +1,110 @@ +#include "video_buffer.h" + +#include +#include +#include +#include + +#include "config.h" +#include "lock_util.h" +#include "log.h" + +SDL_bool video_buffer_init(struct video_buffer *vb) { + if (!(vb->decoding_frame = av_frame_alloc())) { + goto error_0; + } + + if (!(vb->rendering_frame = av_frame_alloc())) { + goto error_1; + } + + if (!(vb->mutex = SDL_CreateMutex())) { + goto error_2; + } + +#ifndef SKIP_FRAMES + if (!(vb->rendering_frame_consumed_cond = SDL_CreateCond())) { + SDL_DestroyMutex(vb->mutex); + goto error_2; + } + vb->stopped = SDL_FALSE; +#endif + + // there is initially no rendering frame, so consider it has already been + // consumed + vb->rendering_frame_consumed = SDL_TRUE; + fps_counter_init(&vb->fps_counter); + + return SDL_TRUE; + +error_2: + av_frame_free(&vb->rendering_frame); +error_1: + av_frame_free(&vb->decoding_frame); +error_0: + return SDL_FALSE; +} + +void video_buffer_destroy(struct video_buffer *vb) { +#ifndef SKIP_FRAMES + SDL_DestroyCond(vb->rendering_frame_consumed_cond); +#endif + SDL_DestroyMutex(vb->mutex); + av_frame_free(&vb->rendering_frame); + av_frame_free(&vb->decoding_frame); +} + +static void video_buffer_swap_frames(struct video_buffer *vb) { + AVFrame *tmp = vb->decoding_frame; + vb->decoding_frame = vb->rendering_frame; + vb->rendering_frame = tmp; +} + +SDL_bool video_buffer_offer_decoded_frame(struct video_buffer *vb) { + mutex_lock(vb->mutex); +#ifndef SKIP_FRAMES + // if SKIP_FRAMES is disabled, then the decoder must wait for the current + // frame to be consumed + while (!vb->rendering_frame_consumed && !vb->stopped) { + cond_wait(vb->rendering_frame_consumed_cond, vb->mutex); + } +#else + if (vb->fps_counter.started && !vb->rendering_frame_consumed) { + fps_counter_add_skipped_frame(&vb->fps_counter); + } +#endif + + video_buffer_swap_frames(vb); + + SDL_bool previous_frame_consumed = vb->rendering_frame_consumed; + vb->rendering_frame_consumed = SDL_FALSE; + + mutex_unlock(vb->mutex); + return previous_frame_consumed; +} + +const AVFrame *video_buffer_consume_rendered_frame(struct video_buffer *vb) { + SDL_assert(!vb->rendering_frame_consumed); + vb->rendering_frame_consumed = SDL_TRUE; + if (vb->fps_counter.started) { + fps_counter_add_rendered_frame(&vb->fps_counter); + } +#ifndef SKIP_FRAMES + // if SKIP_FRAMES is disabled, then notify the decoder the current frame is + // consumed, so that it may push a new one + cond_signal(vb->rendering_frame_consumed_cond); +#endif + return vb->rendering_frame; +} + +void video_buffer_stop(struct video_buffer *vb) { +#ifdef SKIP_FRAMES + (void) vb; // unused +#else + mutex_lock(vb->mutex); + vb->stopped = SDL_TRUE; + mutex_unlock(vb->mutex); + // wake up blocking wait + cond_signal(vb->rendering_frame_consumed_cond); +#endif +} diff --git a/app/src/frames.h b/app/src/video_buffer.h similarity index 65% rename from app/src/frames.h rename to app/src/video_buffer.h index 437838fc..5c19557d 100644 --- a/app/src/frames.h +++ b/app/src/video_buffer.h @@ -1,5 +1,5 @@ -#ifndef FRAMES_H -#define FRAMES_H +#ifndef VIDEO_BUFFER_H +#define VIDEO_BUFFER_H #include #include @@ -10,7 +10,7 @@ // forward declarations typedef struct AVFrame AVFrame; -struct frames { +struct video_buffer { AVFrame *decoding_frame; AVFrame *rendering_frame; SDL_mutex *mutex; @@ -22,21 +22,21 @@ struct frames { struct fps_counter fps_counter; }; -SDL_bool frames_init(struct frames *frames); -void frames_destroy(struct frames *frames); +SDL_bool video_buffer_init(struct video_buffer *vb); +void video_buffer_destroy(struct video_buffer *vb); -// set the decoder frame as ready for rendering +// set the decoded frame as ready for rendering // this function locks frames->mutex during its execution // returns true if the previous frame had been consumed -SDL_bool frames_offer_decoded_frame(struct frames *frames); +SDL_bool video_buffer_offer_decoded_frame(struct video_buffer *vb); // mark the rendering frame as consumed and return it // MUST be called with frames->mutex locked!!! // the caller is expected to render the returned frame to some texture before // unlocking frames->mutex -const AVFrame *frames_consume_rendered_frame(struct frames *frames); +const AVFrame *video_buffer_consume_rendered_frame(struct video_buffer *vb); // wake up and avoid any blocking call -void frames_stop(struct frames *frames); +void video_buffer_stop(struct video_buffer *vb); #endif From 84270e2d1811924f1abc3917739d8d55c69611d4 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 17:01:52 +0100 Subject: [PATCH 04/24] Rename "stop" to "interrupt" The purpose of video_buffer_stop() is to interrupt any blocking call, so rename it to video_buffer_interrupt(). --- app/src/decoder.c | 2 +- app/src/video_buffer.c | 8 ++++---- app/src/video_buffer.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index adc59a30..a4a5beca 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -317,7 +317,7 @@ SDL_bool decoder_start(struct decoder *decoder) { } void decoder_stop(struct decoder *decoder) { - video_buffer_stop(decoder->video_buffer); + video_buffer_interrupt(decoder->video_buffer); } void decoder_join(struct decoder *decoder) { diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index f2a288d4..248b450a 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -27,7 +27,7 @@ SDL_bool video_buffer_init(struct video_buffer *vb) { SDL_DestroyMutex(vb->mutex); goto error_2; } - vb->stopped = SDL_FALSE; + vb->interrupted = SDL_FALSE; #endif // there is initially no rendering frame, so consider it has already been @@ -65,7 +65,7 @@ SDL_bool video_buffer_offer_decoded_frame(struct video_buffer *vb) { #ifndef SKIP_FRAMES // if SKIP_FRAMES is disabled, then the decoder must wait for the current // frame to be consumed - while (!vb->rendering_frame_consumed && !vb->stopped) { + while (!vb->rendering_frame_consumed && !vb->interrupted) { cond_wait(vb->rendering_frame_consumed_cond, vb->mutex); } #else @@ -97,12 +97,12 @@ const AVFrame *video_buffer_consume_rendered_frame(struct video_buffer *vb) { return vb->rendering_frame; } -void video_buffer_stop(struct video_buffer *vb) { +void video_buffer_interrupt(struct video_buffer *vb) { #ifdef SKIP_FRAMES (void) vb; // unused #else mutex_lock(vb->mutex); - vb->stopped = SDL_TRUE; + vb->interrupted = SDL_TRUE; mutex_unlock(vb->mutex); // wake up blocking wait cond_signal(vb->rendering_frame_consumed_cond); diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index 5c19557d..4ad422f8 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -15,7 +15,7 @@ struct video_buffer { AVFrame *rendering_frame; SDL_mutex *mutex; #ifndef SKIP_FRAMES - SDL_bool stopped; + SDL_bool interrupted; SDL_cond *rendering_frame_consumed_cond; #endif SDL_bool rendering_frame_consumed; @@ -37,6 +37,6 @@ SDL_bool video_buffer_offer_decoded_frame(struct video_buffer *vb); const AVFrame *video_buffer_consume_rendered_frame(struct video_buffer *vb); // wake up and avoid any blocking call -void video_buffer_stop(struct video_buffer *vb); +void video_buffer_interrupt(struct video_buffer *vb); #endif From bcd4090d5152ee87e5c1b000f178ea36f79c7aff Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 16:02:01 +0100 Subject: [PATCH 05/24] Fix recording with old decoding/encoding API The deprecated avcodec_decode_video2() should always the whole packet, so there is no need to loop (cf doc/examples/demuxing_decoding.c in FFmpeg). This hack changed the packet size and data pointer. This broke recording which used the same packet. --- app/src/decoder.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index a4a5beca..c2008834 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -237,19 +237,15 @@ static int run_decoder(void *data) { goto run_quit; } #else - while (packet.size > 0) { - int got_picture; - int len = avcodec_decode_video2(codec_ctx, decoder->video_buffer->decoding_frame, &got_picture, &packet); - if (len < 0) { - LOGE("Could not decode video packet: %d", len); - av_packet_unref(&packet); - goto run_quit; - } - if (got_picture) { - push_frame(decoder); - } - packet.size -= len; - packet.data += len; + int got_picture; + int len = avcodec_decode_video2(codec_ctx, decoder->video_buffer->decoding_frame, &got_picture, &packet); + if (len < 0) { + LOGE("Could not decode video packet: %d", len); + av_packet_unref(&packet); + goto run_quit; + } + if (got_picture) { + push_frame(decoder); } #endif From 8aeb5c0e3ccb43864d3ce0bd4d8af8f83d11e5d6 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 18:09:55 +0100 Subject: [PATCH 06/24] Fix cleanup order The order of cleanup was not the reverse as the initialization order. As a consequence, recorder_destroy() could theoretically be called even if recorder_init() failed. --- app/src/scrcpy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index fa347bf5..ed91479d 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -291,14 +291,14 @@ finally_stop_decoder: // stop the server before decoder_join() to wake up the decoder server_stop(&server); decoder_join(&decoder); -finally_destroy_file_handler: - file_handler_stop(&file_handler); - file_handler_join(&file_handler); - file_handler_destroy(&file_handler); finally_destroy_recorder: if (options->record_filename) { recorder_destroy(&recorder); } +finally_destroy_file_handler: + file_handler_stop(&file_handler); + file_handler_join(&file_handler); + file_handler_destroy(&file_handler); finally_destroy_video_buffer: video_buffer_destroy(&video_buffer); finally_destroy_server: From e7b7b083aad8c2e016cd5207988f5775cdaa19e9 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 18:18:12 +0100 Subject: [PATCH 07/24] Store the recording request in a local bool This avoids to test explicitly whether options->record_filename is NULL. --- app/src/scrcpy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index ed91479d..6880ee90 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -174,10 +174,10 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) { } SDL_bool scrcpy(const struct scrcpy_options *options) { - SDL_bool send_frame_meta = !!options->record_filename; + SDL_bool record = !!options->record_filename; if (!server_start(&server, options->serial, options->port, options->max_size, options->bit_rate, options->crop, - send_frame_meta)) { + record)) { return SDL_FALSE; } @@ -228,7 +228,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { } struct recorder *rec = NULL; - if (options->record_filename) { + if (record) { if (!recorder_init(&recorder, options->record_filename, options->record_format, @@ -292,7 +292,7 @@ finally_stop_decoder: server_stop(&server); decoder_join(&decoder); finally_destroy_recorder: - if (options->record_filename) { + if (record) { recorder_destroy(&recorder); } finally_destroy_file_handler: From e6e011baafa9641a1d2b4419f36ef1dc975d479a Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 16:43:43 +0100 Subject: [PATCH 08/24] Add stream layer The decoder initially read from the socket, decoded the video and sent the decoded frames to the screen: +---------+ +----------+ socket ---> | decoder | ---> | screen | +---------+ +----------+ The design was simple, but the decoder had several responsabilities. Then we added the recording feature, so we added a recorder, which reused the packets received from the socket managed by the decoder: +----------+ ---> | screen | +---------+ / +----------+ socket ---> | decoder | ---- +---------+ \ +----------+ ---> | recorder | +----------+ This lack of separation of concerns now have concrete implications: we could not (properly) disable the decoder/display to only record the video. Therefore, split the decoder to extract the stream: +----------+ +----------+ ---> | decoder | ---> | screen | +---------+ / +----------+ +----------+ socket ---> | stream | ---- +---------+ \ +----------+ ---> | recorder | +----------+ This will allow to record the stream without decoding the video. --- app/meson.build | 1 + app/src/decoder.c | 330 ++++++++-------------------------------------- app/src/decoder.h | 31 ++--- app/src/events.h | 2 +- app/src/scrcpy.c | 26 ++-- app/src/stream.c | 275 ++++++++++++++++++++++++++++++++++++++ app/src/stream.h | 35 +++++ 7 files changed, 388 insertions(+), 312 deletions(-) create mode 100644 app/src/stream.c create mode 100644 app/src/stream.h diff --git a/app/meson.build b/app/meson.build index 4c4c807b..5942fd08 100644 --- a/app/meson.build +++ b/app/meson.build @@ -17,6 +17,7 @@ src = [ 'src/server.c', 'src/str_util.c', 'src/tiny_xpm.c', + 'src/stream.c', 'src/video_buffer.c', ] diff --git a/app/src/decoder.c b/app/src/decoder.c index c2008834..ef375fad 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -17,121 +17,6 @@ #include "recorder.h" #include "video_buffer.h" -#define BUFSIZE 0x10000 - -#define HEADER_SIZE 12 -#define NO_PTS UINT64_C(-1) - -static struct frame_meta *frame_meta_new(uint64_t pts) { - struct frame_meta *meta = malloc(sizeof(*meta)); - if (!meta) { - return meta; - } - meta->pts = pts; - meta->next = NULL; - return meta; -} - -static void frame_meta_delete(struct frame_meta *frame_meta) { - free(frame_meta); -} - -static SDL_bool receiver_state_push_meta(struct receiver_state *state, - uint64_t pts) { - struct frame_meta *frame_meta = frame_meta_new(pts); - if (!frame_meta) { - return SDL_FALSE; - } - - // append to the list - // (iterate to find the last item, in practice the list should be tiny) - struct frame_meta **p = &state->frame_meta_queue; - while (*p) { - p = &(*p)->next; - } - *p = frame_meta; - return SDL_TRUE; -} - -static uint64_t receiver_state_take_meta(struct receiver_state *state) { - struct frame_meta *frame_meta = state->frame_meta_queue; // first item - SDL_assert(frame_meta); // must not be empty - uint64_t pts = frame_meta->pts; - state->frame_meta_queue = frame_meta->next; // remove the item - frame_meta_delete(frame_meta); - return pts; -} - -static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { - struct decoder *decoder = opaque; - struct receiver_state *state = &decoder->receiver_state; - - // The video stream contains raw packets, without time information. When we - // record, we retrieve the timestamps separately, from a "meta" header - // added by the server before each raw packet. - // - // The "meta" header length is 12 bytes: - // [. . . . . . . .|. . . .]. . . . . . . . . . . . . . . ... - // <-------------> <-----> <-----------------------------... - // PTS packet raw packet - // size - // - // It is followed by bytes containing the packet/frame. - - if (!state->remaining) { -#define HEADER_SIZE 12 - uint8_t header[HEADER_SIZE]; - ssize_t r = net_recv_all(decoder->video_socket, header, HEADER_SIZE); - if (r == -1) { - return AVERROR(errno); - } - if (r == 0) { - return AVERROR_EOF; - } - // no partial read (net_recv_all()) - SDL_assert_release(r == HEADER_SIZE); - - uint64_t pts = buffer_read64be(header); - state->remaining = buffer_read32be(&header[8]); - - if (pts != NO_PTS && !receiver_state_push_meta(state, pts)) { - LOGE("Could not store PTS for recording"); - // we cannot save the PTS, the recording would be broken - return AVERROR(ENOMEM); - } - } - - SDL_assert(state->remaining); - - if (buf_size > state->remaining) - buf_size = state->remaining; - - ssize_t r = net_recv(decoder->video_socket, buf, buf_size); - if (r == -1) { - return AVERROR(errno); - } - if (r == 0) { - return AVERROR_EOF; - } - - SDL_assert(state->remaining >= r); - state->remaining -= r; - - return r; -} - -static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) { - struct decoder *decoder = opaque; - ssize_t r = net_recv(decoder->video_socket, buf, buf_size); - if (r == -1) { - return AVERROR(errno); - } - if (r == 0) { - return AVERROR_EOF; - } - return r; -} - // set the decoded frame as ready for rendering, and notify static void push_frame(struct decoder *decoder) { SDL_bool previous_frame_consumed = video_buffer_offer_decoded_frame(decoder->video_buffer); @@ -145,177 +30,66 @@ static void push_frame(struct decoder *decoder) { SDL_PushEvent(&new_frame_event); } -static void notify_stopped(void) { - SDL_Event stop_event; - stop_event.type = EVENT_DECODER_STOPPED; - SDL_PushEvent(&stop_event); -} - -static int run_decoder(void *data) { - struct decoder *decoder = data; - - AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264); - if (!codec) { - LOGE("H.264 decoder not found"); - goto run_end; - } - - AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); - if (!codec_ctx) { - LOGC("Could not allocate decoder context"); - goto run_end; - } - - if (avcodec_open2(codec_ctx, codec, NULL) < 0) { - LOGE("Could not open H.264 codec"); - goto run_finally_free_codec_ctx; - } - - AVFormatContext *format_ctx = avformat_alloc_context(); - if (!format_ctx) { - LOGC("Could not allocate format context"); - goto run_finally_close_codec; - } - - unsigned char *buffer = av_malloc(BUFSIZE); - if (!buffer) { - LOGC("Could not allocate buffer"); - goto run_finally_free_format_ctx; - } - - // initialize the receiver state - decoder->receiver_state.frame_meta_queue = NULL; - decoder->receiver_state.remaining = 0; - - // if recording is enabled, a "header" is sent between raw packets - int (*read_packet)(void *, uint8_t *, int) = - decoder->recorder ? read_packet_with_meta : read_raw_packet; - AVIOContext *avio_ctx = avio_alloc_context(buffer, BUFSIZE, 0, decoder, - read_packet, NULL, NULL); - if (!avio_ctx) { - LOGC("Could not allocate avio context"); - // avformat_open_input takes ownership of 'buffer' - // so only free the buffer before avformat_open_input() - av_free(buffer); - goto run_finally_free_format_ctx; - } - - format_ctx->pb = avio_ctx; - - if (avformat_open_input(&format_ctx, NULL, NULL, NULL) < 0) { - LOGE("Could not open video stream"); - goto run_finally_free_avio_ctx; - } - - if (decoder->recorder && - !recorder_open(decoder->recorder, codec)) { - LOGE("Could not open recorder"); - goto run_finally_close_input; - } - - AVPacket packet; - av_init_packet(&packet); - packet.data = NULL; - packet.size = 0; - - while (!av_read_frame(format_ctx, &packet)) { -// the new decoding/encoding API has been introduced by: -// -#ifdef SCRCPY_LAVF_HAS_NEW_ENCODING_DECODING_API - int ret; - if ((ret = avcodec_send_packet(codec_ctx, &packet)) < 0) { - LOGE("Could not send video packet: %d", ret); - goto run_quit; - } - ret = avcodec_receive_frame(codec_ctx, decoder->video_buffer->decoding_frame); - if (!ret) { - // a frame was received - push_frame(decoder); - } else if (ret != AVERROR(EAGAIN)) { - LOGE("Could not receive video frame: %d", ret); - av_packet_unref(&packet); - goto run_quit; - } -#else - int got_picture; - int len = avcodec_decode_video2(codec_ctx, decoder->video_buffer->decoding_frame, &got_picture, &packet); - if (len < 0) { - LOGE("Could not decode video packet: %d", len); - av_packet_unref(&packet); - goto run_quit; - } - if (got_picture) { - push_frame(decoder); - } -#endif - - if (decoder->recorder) { - // we retrieve the PTS in order they were received, so they will - // be assigned to the correct frame - uint64_t pts = receiver_state_take_meta(&decoder->receiver_state); - packet.pts = pts; - packet.dts = pts; - - // no need to rescale with av_packet_rescale_ts(), the timestamps - // are in microseconds both in input and output - if (!recorder_write(decoder->recorder, &packet)) { - LOGE("Could not write frame to output file"); - av_packet_unref(&packet); - goto run_quit; - } - } - - av_packet_unref(&packet); - - if (avio_ctx->eof_reached) { - break; - } - } - - LOGD("End of frames"); - -run_quit: - if (decoder->recorder) { - recorder_close(decoder->recorder); - } -run_finally_close_input: - avformat_close_input(&format_ctx); -run_finally_free_avio_ctx: - av_free(avio_ctx->buffer); - av_free(avio_ctx); -run_finally_free_format_ctx: - avformat_free_context(format_ctx); -run_finally_close_codec: - avcodec_close(codec_ctx); -run_finally_free_codec_ctx: - avcodec_free_context(&codec_ctx); - notify_stopped(); -run_end: - return 0; -} - -void decoder_init(struct decoder *decoder, struct video_buffer *vb, - socket_t video_socket, struct recorder *recorder) { +void decoder_init(struct decoder *decoder, struct video_buffer *vb) { decoder->video_buffer = vb; - decoder->video_socket = video_socket; - decoder->recorder = recorder; } -SDL_bool decoder_start(struct decoder *decoder) { - LOGD("Starting decoder thread"); - - decoder->thread = SDL_CreateThread(run_decoder, "video_decoder", decoder); - if (!decoder->thread) { - LOGC("Could not start decoder thread"); +SDL_bool decoder_open(struct decoder *decoder, AVCodec *codec) { + decoder->codec_ctx = avcodec_alloc_context3(codec); + if (!decoder->codec_ctx) { + LOGC("Could not allocate decoder context"); return SDL_FALSE; } + + if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) { + LOGE("Could not open codec"); + avcodec_free_context(&decoder->codec_ctx); + return SDL_FALSE; + } + return SDL_TRUE; } -void decoder_stop(struct decoder *decoder) { - video_buffer_interrupt(decoder->video_buffer); +void decoder_close(struct decoder *decoder) { + avcodec_close(decoder->codec_ctx); + avcodec_free_context(&decoder->codec_ctx); } -void decoder_join(struct decoder *decoder) { - SDL_WaitThread(decoder->thread, NULL); +SDL_bool decoder_push(struct decoder *decoder, AVPacket *packet) { +// the new decoding/encoding API has been introduced by: +// +#ifdef SCRCPY_LAVF_HAS_NEW_ENCODING_DECODING_API + int ret; + if ((ret = avcodec_send_packet(decoder->codec_ctx, packet)) < 0) { + LOGE("Could not send video packet: %d", ret); + return SDL_FALSE; + } + ret = avcodec_receive_frame(decoder->codec_ctx, + decoder->video_buffer->decoding_frame); + if (!ret) { + // a frame was received + push_frame(decoder); + } else if (ret != AVERROR(EAGAIN)) { + LOGE("Could not receive video frame: %d", ret); + return SDL_FALSE; + } +#else + int got_picture; + int len = avcodec_decode_video2(decoder->codec_ctx, + decoder->video_buffer->decoding_frame, + &got_picture, + packet); + if (len < 0) { + LOGE("Could not decode video packet: %d", len); + return SDL_FALSE; + } + if (got_picture) { + push_frame(decoder); + } +#endif + return SDL_TRUE; +} + +void decoder_interrupt(struct decoder *decoder) { + video_buffer_interrupt(decoder->video_buffer); } diff --git a/app/src/decoder.h b/app/src/decoder.h index 240dab00..ac8308c7 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -1,35 +1,22 @@ #ifndef DECODER_H #define DECODER_H +#include #include -#include - -#include "common.h" -#include "net.h" struct video_buffer; -struct frame_meta { - uint64_t pts; - struct frame_meta *next; -}; - struct decoder { struct video_buffer *video_buffer; - socket_t video_socket; - SDL_Thread *thread; - struct recorder *recorder; - struct receiver_state { - // meta (in order) for frames not consumed yet - struct frame_meta *frame_meta_queue; - size_t remaining; // remaining bytes to receive for the current frame - } receiver_state; + AVCodecContext *codec_ctx; }; -void decoder_init(struct decoder *decoder, struct video_buffer *vb, - socket_t video_socket, struct recorder *recoder); -SDL_bool decoder_start(struct decoder *decoder); -void decoder_stop(struct decoder *decoder); -void decoder_join(struct decoder *decoder); +void decoder_init(struct decoder *decoder, struct video_buffer *vb); + +SDL_bool decoder_open(struct decoder *decoder, AVCodec *codec); +void decoder_close(struct decoder *decoder); + +SDL_bool decoder_push(struct decoder *decoder, AVPacket *packet); +void decoder_interrupt(struct decoder *decoder); #endif diff --git a/app/src/events.h b/app/src/events.h index ff0c1a05..e9512048 100644 --- a/app/src/events.h +++ b/app/src/events.h @@ -1,3 +1,3 @@ #define EVENT_NEW_SESSION SDL_USEREVENT #define EVENT_NEW_FRAME (SDL_USEREVENT + 1) -#define EVENT_DECODER_STOPPED (SDL_USEREVENT + 2) +#define EVENT_STREAM_STOPPED (SDL_USEREVENT + 2) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 6880ee90..2bb9b280 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -22,16 +22,18 @@ #include "recorder.h" #include "screen.h" #include "server.h" +#include "stream.h" #include "tiny_xpm.h" #include "video_buffer.h" static struct server server = SERVER_INITIALIZER; static struct screen screen = SCREEN_INITIALIZER; static struct video_buffer video_buffer; +static struct stream stream; static struct decoder decoder; +static struct recorder recorder; static struct controller controller; static struct file_handler file_handler; -static struct recorder recorder; static struct input_manager input_manager = { .controller = &controller, @@ -70,8 +72,8 @@ static SDL_bool event_loop(void) { SDL_Event event; while (SDL_WaitEvent(&event)) { switch (event.type) { - case EVENT_DECODER_STOPPED: - LOGD("Video decoder stopped"); + case EVENT_STREAM_STOPPED: + LOGD("Video stream stopped"); return SDL_FALSE; case SDL_QUIT: LOGD("User requested to quit"); @@ -227,6 +229,8 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { goto finally_destroy_video_buffer; } + decoder_init(&decoder, &video_buffer); + struct recorder *rec = NULL; if (record) { if (!recorder_init(&recorder, @@ -242,11 +246,11 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { av_log_set_callback(av_log_callback); - decoder_init(&decoder, &video_buffer, device_socket, rec); + stream_init(&stream, device_socket, &decoder, rec); // now we consumed the header values, the socket receives the video stream - // start the decoder - if (!decoder_start(&decoder)) { + // start the stream + if (!stream_start(&stream)) { ret = SDL_FALSE; server_stop(&server); goto finally_destroy_recorder; @@ -254,7 +258,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { if (!controller_init(&controller, device_socket)) { ret = SDL_FALSE; - goto finally_stop_decoder; + goto finally_stop_stream; } if (!controller_start(&controller)) { @@ -286,11 +290,11 @@ finally_stop_and_join_controller: controller_join(&controller); finally_destroy_controller: controller_destroy(&controller); -finally_stop_decoder: - decoder_stop(&decoder); - // stop the server before decoder_join() to wake up the decoder +finally_stop_stream: + stream_stop(&stream); + // stop the server before stream_join() to wake up the stream server_stop(&server); - decoder_join(&decoder); + stream_join(&stream); finally_destroy_recorder: if (record) { recorder_destroy(&recorder); diff --git a/app/src/stream.c b/app/src/stream.c new file mode 100644 index 00000000..73bb95d1 --- /dev/null +++ b/app/src/stream.c @@ -0,0 +1,275 @@ +#include "stream.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include "config.h" +#include "buffer_util.h" +#include "decoder.h" +#include "events.h" +#include "lock_util.h" +#include "log.h" +#include "recorder.h" + +#define BUFSIZE 0x10000 + +#define HEADER_SIZE 12 +#define NO_PTS UINT64_C(-1) + +static struct frame_meta *frame_meta_new(Uint64 pts) { + struct frame_meta *meta = malloc(sizeof(*meta)); + if (!meta) { + return meta; + } + meta->pts = pts; + meta->next = NULL; + return meta; +} + +static void frame_meta_delete(struct frame_meta *frame_meta) { + free(frame_meta); +} + +static SDL_bool receiver_state_push_meta(struct receiver_state *state, + uint64_t pts) { + struct frame_meta *frame_meta = frame_meta_new(pts); + if (!frame_meta) { + return SDL_FALSE; + } + + // append to the list + // (iterate to find the last item, in practice the list should be tiny) + struct frame_meta **p = &state->frame_meta_queue; + while (*p) { + p = &(*p)->next; + } + *p = frame_meta; + return SDL_TRUE; +} + +static uint64_t receiver_state_take_meta(struct receiver_state *state) { + struct frame_meta *frame_meta = state->frame_meta_queue; // first item + SDL_assert(frame_meta); // must not be empty + uint64_t pts = frame_meta->pts; + state->frame_meta_queue = frame_meta->next; // remove the item + frame_meta_delete(frame_meta); + return pts; +} + +static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { + struct stream *stream = opaque; + struct receiver_state *state = &stream->receiver_state; + + // The video stream contains raw packets, without time information. When we + // record, we retrieve the timestamps separately, from a "meta" header + // added by the server before each raw packet. + // + // The "meta" header length is 12 bytes: + // [. . . . . . . .|. . . .]. . . . . . . . . . . . . . . ... + // <-------------> <-----> <-----------------------------... + // PTS packet raw packet + // size + // + // It is followed by bytes containing the packet/frame. + + if (!state->remaining) { +#define HEADER_SIZE 12 + uint8_t header[HEADER_SIZE]; + ssize_t r = net_recv_all(stream->socket, header, HEADER_SIZE); + if (r == -1) { + return AVERROR(errno); + } + if (r == 0) { + return AVERROR_EOF; + } + // no partial read (net_recv_all()) + SDL_assert_release(r == HEADER_SIZE); + + uint64_t pts = buffer_read64be(header); + state->remaining = buffer_read32be(&header[8]); + + if (pts != NO_PTS && !receiver_state_push_meta(state, pts)) { + LOGE("Could not store PTS for recording"); + // we cannot save the PTS, the recording would be broken + return AVERROR(ENOMEM); + } + } + + SDL_assert(state->remaining); + + if (buf_size > state->remaining) { + buf_size = state->remaining; + } + + ssize_t r = net_recv(stream->socket, buf, buf_size); + if (r == -1) { + return AVERROR(errno); + } + if (r == 0) { + return AVERROR_EOF; + } + + SDL_assert(state->remaining >= r); + state->remaining -= r; + + return r; +} + +static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) { + struct stream *stream = opaque; + ssize_t r = net_recv(stream->socket, buf, buf_size); + if (r == -1) { + return AVERROR(errno); + } + if (r == 0) { + return AVERROR_EOF; + } + return r; +} + +static void notify_stopped(void) { + SDL_Event stop_event; + stop_event.type = EVENT_STREAM_STOPPED; + SDL_PushEvent(&stop_event); +} + +static int run_stream(void *data) { + struct stream *stream = data; + + AVFormatContext *format_ctx = avformat_alloc_context(); + if (!format_ctx) { + LOGC("Could not allocate format context"); + goto end; + } + + unsigned char *buffer = av_malloc(BUFSIZE); + if (!buffer) { + LOGC("Could not allocate buffer"); + goto finally_free_format_ctx; + } + + // initialize the receiver state + stream->receiver_state.frame_meta_queue = NULL; + stream->receiver_state.remaining = 0; + + // if recording is enabled, a "header" is sent between raw packets + int (*read_packet)(void *, uint8_t *, int) = + stream->recorder ? read_packet_with_meta : read_raw_packet; + AVIOContext *avio_ctx = avio_alloc_context(buffer, BUFSIZE, 0, stream, + read_packet, NULL, NULL); + if (!avio_ctx) { + LOGC("Could not allocate avio context"); + // avformat_open_input takes ownership of 'buffer' + // so only free the buffer before avformat_open_input() + av_free(buffer); + goto finally_free_format_ctx; + } + + format_ctx->pb = avio_ctx; + + if (avformat_open_input(&format_ctx, NULL, NULL, NULL) < 0) { + LOGE("Could not open video stream"); + goto finally_free_avio_ctx; + } + + AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264); + if (!codec) { + LOGE("H.264 decoder not found"); + goto end; + } + + if (stream->decoder && !decoder_open(stream->decoder, codec)) { + LOGE("Could not open decoder"); + goto finally_close_input; + } + + if (stream->recorder && !recorder_open(stream->recorder, codec)) { + LOGE("Could not open recorder"); + goto finally_close_input; + } + + AVPacket packet; + av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + + while (!av_read_frame(format_ctx, &packet)) { + if (stream->decoder && !decoder_push(stream->decoder, &packet)) { + av_packet_unref(&packet); + goto quit; + } + + if (stream->recorder) { + // we retrieve the PTS in order they were received, so they will + // be assigned to the correct frame + Uint64 pts = receiver_state_take_meta(&stream->receiver_state); + packet.pts = pts; + packet.dts = pts; + + // no need to rescale with av_packet_rescale_ts(), the timestamps + // are in microseconds both in input and output + if (!recorder_write(stream->recorder, &packet)) { + LOGE("Could not write frame to output file"); + av_packet_unref(&packet); + goto quit; + } + } + + av_packet_unref(&packet); + + if (avio_ctx->eof_reached) { + break; + } + } + + LOGD("End of frames"); + +quit: + if (stream->recorder) { + recorder_close(stream->recorder); + } +finally_close_input: + avformat_close_input(&format_ctx); +finally_free_avio_ctx: + av_free(avio_ctx->buffer); + av_free(avio_ctx); +finally_free_format_ctx: + avformat_free_context(format_ctx); +end: + notify_stopped(); + return 0; +} + +void stream_init(struct stream *stream, socket_t socket, + struct decoder *decoder, struct recorder *recorder) { + stream->socket = socket; + stream->decoder = decoder, + stream->recorder = recorder; +} + +SDL_bool stream_start(struct stream *stream) { + LOGD("Starting stream thread"); + + stream->thread = SDL_CreateThread(run_stream, "stream", stream); + if (!stream->thread) { + LOGC("Could not start stream thread"); + return SDL_FALSE; + } + return SDL_TRUE; +} + +void stream_stop(struct stream *stream) { + if (stream->decoder) { + decoder_interrupt(stream->decoder); + } +} + +void stream_join(struct stream *stream) { + SDL_WaitThread(stream->thread, NULL); +} diff --git a/app/src/stream.h b/app/src/stream.h new file mode 100644 index 00000000..ef78b321 --- /dev/null +++ b/app/src/stream.h @@ -0,0 +1,35 @@ +#ifndef STREAM_H +#define STREAM_H + +#include +#include + +#include "net.h" + +struct video_buffer; + +struct frame_meta { + Uint64 pts; + struct frame_meta *next; +}; + +struct stream { + socket_t socket; + struct video_buffer *video_buffer; + SDL_Thread *thread; + struct decoder *decoder; + struct recorder *recorder; + struct receiver_state { + // meta (in order) for frames not consumed yet + struct frame_meta *frame_meta_queue; + size_t remaining; // remaining bytes to receive for the current frame + } receiver_state; +}; + +void stream_init(struct stream *stream, socket_t socket, + struct decoder *decoder, struct recorder *recorder); +SDL_bool stream_start(struct stream *stream); +void stream_stop(struct stream *stream); +void stream_join(struct stream *stream); + +#endif From 421a1141e29cfa28e2ca90ac51e2d7387082f2fa Mon Sep 17 00:00:00 2001 From: CapsLock Date: Fri, 1 Feb 2019 22:53:24 +0100 Subject: [PATCH 09/24] Add a new option: -n/--no-window This option will allow scrcpy to record the stream without display. Signed-off-by: Romain Vimont --- app/src/main.c | 21 ++++++++++++++++++++- app/src/scrcpy.h | 1 + app/src/screen.h | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app/src/main.c b/app/src/main.c index f18b3aaf..c4ffad24 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -16,6 +16,7 @@ struct args { const char *record_filename; enum recorder_format record_format; SDL_bool fullscreen; + SDL_bool no_window; SDL_bool help; SDL_bool version; SDL_bool show_touches; @@ -57,6 +58,9 @@ static void usage(const char *arg0) { " is preserved.\n" " Default is %d%s.\n" "\n" + " -n, --no-window\n" + " Do not show window (only when screen recording is enabled).\n" + "\n" " -p, --port port\n" " Set the TCP port the client listens on.\n" " Default is %d.\n" @@ -260,6 +264,7 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { {"fullscreen", no_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"max-size", required_argument, NULL, 'm'}, + {"no-window", no_argument, NULL, 'n'}, {"port", required_argument, NULL, 'p'}, {"record", required_argument, NULL, 'r'}, {"record-format", required_argument, NULL, 'f'}, @@ -269,7 +274,7 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { {NULL, 0, NULL, 0 }, }; int c; - while ((c = getopt_long(argc, argv, "b:c:fF:hm:p:r:s:tTv", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "b:c:fF:hm:np:r:s:tTv", long_options, NULL)) != -1) { switch (c) { case 'b': if (!parse_bit_rate(optarg, &args->bit_rate)) { @@ -295,6 +300,9 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { return SDL_FALSE; } break; + case 'n': + args->no_window = SDL_TRUE; + break; case 'p': if (!parse_port(optarg, &args->port)) { return SDL_FALSE; @@ -321,6 +329,16 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { } } + if (args->no_window && !args->record_filename) { + LOGE("-n/--no-window requires screen recording (-r/--record)"); + return SDL_FALSE; + } + + if (args->no_window && args->fullscreen) { + LOGE("-f/--fullscreen-window is incompatible with -n/--no-window"); + return SDL_FALSE; + } + int index = optind; if (index < argc) { LOGE("Unexpected additional argument: %s", argv[index]); @@ -401,6 +419,7 @@ int main(int argc, char *argv[]) { .show_touches = args.show_touches, .fullscreen = args.fullscreen, .always_on_top = args.always_on_top, + .no_window = args.no_window, }; int res = scrcpy(&options) ? 0 : 1; diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index aba1f336..ff7f482a 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -15,6 +15,7 @@ struct scrcpy_options { SDL_bool show_touches; SDL_bool fullscreen; SDL_bool always_on_top; + SDL_bool no_window; }; SDL_bool scrcpy(const struct scrcpy_options *options); diff --git a/app/src/screen.h b/app/src/screen.h index 4a13bfca..f857e981 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -17,6 +17,7 @@ struct screen { struct size windowed_window_size; SDL_bool has_frame; SDL_bool fullscreen; + SDL_bool no_window; }; #define SCREEN_INITIALIZER { \ @@ -33,6 +34,7 @@ struct screen { }, \ .has_frame = SDL_FALSE, \ .fullscreen = SDL_FALSE, \ + .no_window = SDL_FALSE, \ } // init SDL and set appropriate hints From 89812e4eee47a49a92cf79d9e48c1f763505d0a6 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 18:06:29 +0100 Subject: [PATCH 10/24] Implement the --no-window flag Disable decoder, screen (display), file_handler and controller when --no-window is requested. --- app/src/scrcpy.c | 84 ++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 2bb9b280..387ce4e0 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -217,19 +217,25 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { goto finally_destroy_server; } - if (!video_buffer_init(&video_buffer)) { - server_stop(&server); - ret = SDL_FALSE; - goto finally_destroy_server; - } + SDL_bool display = !options->no_window; - if (!file_handler_init(&file_handler, server.serial)) { - ret = SDL_FALSE; - server_stop(&server); - goto finally_destroy_video_buffer; - } + struct decoder *dec = NULL; + if (display) { + if (!video_buffer_init(&video_buffer)) { + server_stop(&server); + ret = SDL_FALSE; + goto finally_destroy_server; + } - decoder_init(&decoder, &video_buffer); + if (!file_handler_init(&file_handler, server.serial)) { + ret = SDL_FALSE; + server_stop(&server); + goto finally_destroy_video_buffer; + } + + decoder_init(&decoder, &video_buffer); + dec = &decoder; + } struct recorder *rec = NULL; if (record) { @@ -246,7 +252,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { av_log_set_callback(av_log_callback); - stream_init(&stream, device_socket, &decoder, rec); + stream_init(&stream, device_socket, dec, rec); // now we consumed the header values, the socket receives the video stream // start the stream @@ -256,19 +262,25 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { goto finally_destroy_recorder; } - if (!controller_init(&controller, device_socket)) { - ret = SDL_FALSE; - goto finally_stop_stream; - } + if (display) { + if (!controller_init(&controller, device_socket)) { + ret = SDL_FALSE; + goto finally_stop_stream; + } - if (!controller_start(&controller)) { - ret = SDL_FALSE; - goto finally_destroy_controller; - } + if (!controller_start(&controller)) { + ret = SDL_FALSE; + goto finally_destroy_controller; + } - if (!screen_init_rendering(&screen, device_name, frame_size, options->always_on_top)) { - ret = SDL_FALSE; - goto finally_stop_and_join_controller; + if (!screen_init_rendering(&screen, device_name, frame_size, options->always_on_top)) { + ret = SDL_FALSE; + goto finally_stop_and_join_controller; + } + + if (options->fullscreen) { + screen_switch_fullscreen(&screen); + } } if (options->show_touches) { @@ -276,20 +288,20 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { show_touches_waited = SDL_TRUE; } - if (options->fullscreen) { - screen_switch_fullscreen(&screen); - } - ret = event_loop(); LOGD("quit..."); screen_destroy(&screen); finally_stop_and_join_controller: - controller_stop(&controller); - controller_join(&controller); + if (display) { + controller_stop(&controller); + controller_join(&controller); + } finally_destroy_controller: - controller_destroy(&controller); + if (display) { + controller_destroy(&controller); + } finally_stop_stream: stream_stop(&stream); // stop the server before stream_join() to wake up the stream @@ -300,11 +312,15 @@ finally_destroy_recorder: recorder_destroy(&recorder); } finally_destroy_file_handler: - file_handler_stop(&file_handler); - file_handler_join(&file_handler); - file_handler_destroy(&file_handler); + if (display) { + file_handler_stop(&file_handler); + file_handler_join(&file_handler); + file_handler_destroy(&file_handler); + } finally_destroy_video_buffer: - video_buffer_destroy(&video_buffer); + if (display) { + video_buffer_destroy(&video_buffer); + } finally_destroy_server: if (options->show_touches) { if (!show_touches_waited) { From ef118cc633943ac8941bed0ec7c3bafe6c59bbbf Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 18:33:31 +0100 Subject: [PATCH 11/24] Describe the --no-window feature in README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index af67a17b..ed40f21a 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,14 @@ scrcpy --record file.mp4 scrcpy -r file.mkv ``` +To disable mirroring while recording: + +```bash +scrcpy --no-window --record file.mp4 +scrcpy -nr file.mkv +# interrupt recording with Ctrl+C +``` + "Skipped frames" are recorded, even if they are not displayed in real time (for performance reasons). Frames are _timestamped_ on the device, so [packet delay variation] does not impact the recorded file. From b2fe00549882a17d8c5c68b33c9756968f7a681d Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 20:10:34 +0100 Subject: [PATCH 12/24] Replace uint64_t by Uint64 for consistency The field pts is declared Uint64 in struct frame_meta. --- app/src/stream.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/stream.c b/app/src/stream.c index 73bb95d1..c75afa0f 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -37,7 +37,7 @@ static void frame_meta_delete(struct frame_meta *frame_meta) { } static SDL_bool receiver_state_push_meta(struct receiver_state *state, - uint64_t pts) { + Uint64 pts) { struct frame_meta *frame_meta = frame_meta_new(pts); if (!frame_meta) { return SDL_FALSE; @@ -53,10 +53,10 @@ static SDL_bool receiver_state_push_meta(struct receiver_state *state, return SDL_TRUE; } -static uint64_t receiver_state_take_meta(struct receiver_state *state) { +static Uint64 receiver_state_take_meta(struct receiver_state *state) { struct frame_meta *frame_meta = state->frame_meta_queue; // first item SDL_assert(frame_meta); // must not be empty - uint64_t pts = frame_meta->pts; + Uint64 pts = frame_meta->pts; state->frame_meta_queue = frame_meta->next; // remove the item frame_meta_delete(frame_meta); return pts; @@ -91,7 +91,7 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { // no partial read (net_recv_all()) SDL_assert_release(r == HEADER_SIZE); - uint64_t pts = buffer_read64be(header); + Uint64 pts = buffer_read64be(header); state->remaining = buffer_read32be(&header[8]); if (pts != NO_PTS && !receiver_state_push_meta(state, pts)) { From aeda583a2c75ebc09862f698892acfd2ccff95d5 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 20:09:56 +0100 Subject: [PATCH 13/24] Update code style Limit source code to 80 chars, and declare functions return type and modifiers on a separate line. This allows to avoid very long lines, and all function names are aligned. (We do this on VLC, and I like it.) --- app/src/buffer_util.h | 12 ++-- app/src/command.c | 32 +++++++---- app/src/command.h | 46 +++++++++++---- app/src/common.h | 3 +- app/src/control_event.c | 29 +++++++--- app/src/control_event.h | 29 +++++++--- app/src/controller.c | 35 ++++++++---- app/src/controller.h | 22 ++++++-- app/src/convert.c | 44 +++++++++------ app/src/convert.h | 31 +++++----- app/src/decoder.c | 21 ++++--- app/src/decoder.h | 17 ++++-- app/src/device.c | 16 ++++-- app/src/device.h | 3 +- app/src/file_handler.c | 64 +++++++++++++-------- app/src/file_handler.h | 25 ++++++--- app/src/fps_counter.c | 24 +++++--- app/src/fps_counter.h | 18 ++++-- app/src/input_manager.c | 95 ++++++++++++++++++++----------- app/src/input_manager.h | 29 ++++++---- app/src/lock_util.c | 12 ++-- app/src/lock_util.h | 15 +++-- app/src/main.c | 36 ++++++++---- app/src/net.c | 27 ++++++--- app/src/net.h | 41 ++++++++++---- app/src/recorder.c | 24 +++++--- app/src/recorder.h | 20 ++++--- app/src/scrcpy.c | 45 +++++++++------ app/src/scrcpy.h | 3 +- app/src/screen.c | 112 ++++++++++++++++++++++++------------- app/src/screen.h | 34 ++++++----- app/src/server.c | 72 +++++++++++++++--------- app/src/server.h | 15 +++-- app/src/str_util.c | 12 ++-- app/src/str_util.h | 12 ++-- app/src/stream.c | 39 ++++++++----- app/src/stream.h | 17 ++++-- app/src/sys/unix/command.c | 12 ++-- app/src/sys/unix/net.c | 9 ++- app/src/sys/win/command.c | 18 ++++-- app/src/sys/win/net.c | 9 ++- app/src/tiny_xpm.c | 6 +- app/src/tiny_xpm.h | 3 +- app/src/video_buffer.c | 18 ++++-- app/src/video_buffer.h | 16 ++++-- 45 files changed, 813 insertions(+), 409 deletions(-) diff --git a/app/src/buffer_util.h b/app/src/buffer_util.h index cfb3fa12..9b2f0780 100644 --- a/app/src/buffer_util.h +++ b/app/src/buffer_util.h @@ -3,23 +3,27 @@ #include -static inline void buffer_write16be(Uint8 *buf, Uint16 value) { +static inline void +buffer_write16be(Uint8 *buf, Uint16 value) { buf[0] = value >> 8; buf[1] = value; } -static inline void buffer_write32be(Uint8 *buf, Uint32 value) { +static inline void +buffer_write32be(Uint8 *buf, Uint32 value) { buf[0] = value >> 24; buf[1] = value >> 16; buf[2] = value >> 8; buf[3] = value; } -static inline Uint32 buffer_read32be(Uint8 *buf) { +static inline Uint32 +buffer_read32be(Uint8 *buf) { return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; } -static inline Uint64 buffer_read64be(Uint8 *buf) { +static inline +Uint64 buffer_read64be(Uint8 *buf) { Uint32 msb = buffer_read32be(buf); Uint32 lsb = buffer_read32be(&buf[4]); return ((Uint64) msb << 32) | lsb; diff --git a/app/src/command.c b/app/src/command.c index b8340ecc..01f82344 100644 --- a/app/src/command.c +++ b/app/src/command.c @@ -10,7 +10,8 @@ static const char *adb_command; -static inline const char *get_adb_command(void) { +static inline const char * +get_adb_command(void) { if (!adb_command) { adb_command = getenv("ADB"); if (!adb_command) @@ -19,7 +20,8 @@ static inline const char *get_adb_command(void) { return adb_command; } -static void show_adb_err_msg(enum process_result err) { +static void +show_adb_err_msg(enum process_result err) { switch (err) { case PROCESS_ERROR_GENERIC: LOGE("Failed to execute adb"); @@ -34,7 +36,8 @@ static void show_adb_err_msg(enum process_result err) { } } -process_t adb_execute(const char *serial, const char *const adb_cmd[], int len) { +process_t +adb_execute(const char *serial, const char *const adb_cmd[], int len) { const char *cmd[len + 4]; int i; process_t process; @@ -57,7 +60,9 @@ process_t adb_execute(const char *serial, const char *const adb_cmd[], int len) return process; } -process_t adb_forward(const char *serial, uint16_t local_port, const char *device_socket_name) { +process_t +adb_forward(const char *serial, uint16_t local_port, + const char *device_socket_name) { char local[4 + 5 + 1]; // tcp:PORT char remote[108 + 14 + 1]; // localabstract:NAME sprintf(local, "tcp:%" PRIu16, local_port); @@ -66,14 +71,17 @@ process_t adb_forward(const char *serial, uint16_t local_port, const char *devic return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd)); } -process_t adb_forward_remove(const char *serial, uint16_t local_port) { +process_t +adb_forward_remove(const char *serial, uint16_t local_port) { char local[4 + 5 + 1]; // tcp:PORT sprintf(local, "tcp:%" PRIu16, local_port); const char *const adb_cmd[] = {"forward", "--remove", local}; return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd)); } -process_t adb_reverse(const char *serial, const char *device_socket_name, uint16_t local_port) { +process_t +adb_reverse(const char *serial, const char *device_socket_name, + uint16_t local_port) { char local[4 + 5 + 1]; // tcp:PORT char remote[108 + 14 + 1]; // localabstract:NAME sprintf(local, "tcp:%" PRIu16, local_port); @@ -82,14 +90,16 @@ process_t adb_reverse(const char *serial, const char *device_socket_name, uint16 return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd)); } -process_t adb_reverse_remove(const char *serial, const char *device_socket_name) { +process_t +adb_reverse_remove(const char *serial, const char *device_socket_name) { char remote[108 + 14 + 1]; // localabstract:NAME snprintf(remote, sizeof(remote), "localabstract:%s", device_socket_name); const char *const adb_cmd[] = {"reverse", "--remove", remote}; return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd)); } -process_t adb_push(const char *serial, const char *local, const char *remote) { +process_t +adb_push(const char *serial, const char *local, const char *remote) { #ifdef __WINDOWS__ // Windows will parse the string, so the paths must be quoted // (see sys/win/command.c) @@ -115,7 +125,8 @@ process_t adb_push(const char *serial, const char *local, const char *remote) { return proc; } -process_t adb_install(const char *serial, const char *local) { +process_t +adb_install(const char *serial, const char *local) { #ifdef __WINDOWS__ // Windows will parse the string, so the local name must be quoted // (see sys/win/command.c) @@ -135,7 +146,8 @@ process_t adb_install(const char *serial, const char *local) { return proc; } -SDL_bool process_check_success(process_t proc, const char *name) { +SDL_bool +process_check_success(process_t proc, const char *name) { if (proc == PROCESS_NONE) { LOGE("Could not execute \"%s\"", name); return SDL_FALSE; diff --git a/app/src/command.h b/app/src/command.h index 6264adf4..835fce25 100644 --- a/app/src/command.h +++ b/app/src/command.h @@ -6,7 +6,8 @@ #ifdef _WIN32 -# include // not needed here, but must never be included AFTER windows.h + // not needed here, but winsock2.h must never be included AFTER windows.h +# include # include # define PRIexitcode "lu" // @@ -38,20 +39,41 @@ enum process_result { PROCESS_ERROR_MISSING_BINARY, }; -enum process_result cmd_execute(const char *path, const char *const argv[], process_t *process); -SDL_bool cmd_terminate(process_t pid); -SDL_bool cmd_simple_wait(process_t pid, exit_code_t *exit_code); +enum process_result +cmd_execute(const char *path, const char *const argv[], process_t *process); -process_t adb_execute(const char *serial, const char *const adb_cmd[], int len); -process_t adb_forward(const char *serial, uint16_t local_port, const char *device_socket_name); -process_t adb_forward_remove(const char *serial, uint16_t local_port); -process_t adb_reverse(const char *serial, const char *device_socket_name, uint16_t local_port); -process_t adb_reverse_remove(const char *serial, const char *device_socket_name); -process_t adb_push(const char *serial, const char *local, const char *remote); -process_t adb_install(const char *serial, const char *local); +SDL_bool +cmd_terminate(process_t pid); + +SDL_bool +cmd_simple_wait(process_t pid, exit_code_t *exit_code); + +process_t +adb_execute(const char *serial, const char *const adb_cmd[], int len); + +process_t +adb_forward(const char *serial, uint16_t local_port, + const char *device_socket_name); + +process_t +adb_forward_remove(const char *serial, uint16_t local_port); + +process_t +adb_reverse(const char *serial, const char *device_socket_name, + uint16_t local_port); + +process_t +adb_reverse_remove(const char *serial, const char *device_socket_name); + +process_t +adb_push(const char *serial, const char *local, const char *remote); + +process_t +adb_install(const char *serial, const char *local); // convenience function to wait for a successful process execution // automatically log process errors with the provided process name -SDL_bool process_check_success(process_t process, const char *name); +SDL_bool +process_check_success(process_t process, const char *name); #endif diff --git a/app/src/common.h b/app/src/common.h index d3d000f9..133f09f5 100644 --- a/app/src/common.h +++ b/app/src/common.h @@ -19,7 +19,8 @@ struct point { struct position { // The video screen size may be different from the real device screen size, - // so store to which size the absolute position apply, to scale it accordingly. + // so store to which size the absolute position apply, to scale it + // accordingly. struct size screen_size; struct point point; }; diff --git a/app/src/control_event.c b/app/src/control_event.c index 015ce786..9ed69b71 100644 --- a/app/src/control_event.c +++ b/app/src/control_event.c @@ -7,14 +7,16 @@ #include "lock_util.h" #include "log.h" -static void write_position(Uint8 *buf, const struct position *position) { +static void +write_position(Uint8 *buf, const struct position *position) { buffer_write32be(&buf[0], position->point.x); buffer_write32be(&buf[4], position->point.y); buffer_write16be(&buf[8], position->screen_size.width); buffer_write16be(&buf[10], position->screen_size.height); } -int control_event_serialize(const struct control_event *event, unsigned char *buf) { +int +control_event_serialize(const struct control_event *event, unsigned char *buf) { buf[0] = event->type; switch (event->type) { case CONTROL_EVENT_TYPE_KEYCODE: @@ -52,28 +54,33 @@ int control_event_serialize(const struct control_event *event, unsigned char *bu } } -void control_event_destroy(struct control_event *event) { +void +control_event_destroy(struct control_event *event) { if (event->type == CONTROL_EVENT_TYPE_TEXT) { SDL_free(event->text_event.text); } } -SDL_bool control_event_queue_is_empty(const struct control_event_queue *queue) { +SDL_bool +control_event_queue_is_empty(const struct control_event_queue *queue) { return queue->head == queue->tail; } -SDL_bool control_event_queue_is_full(const struct control_event_queue *queue) { +SDL_bool +control_event_queue_is_full(const struct control_event_queue *queue) { return (queue->head + 1) % CONTROL_EVENT_QUEUE_SIZE == queue->tail; } -SDL_bool control_event_queue_init(struct control_event_queue *queue) { +SDL_bool +control_event_queue_init(struct control_event_queue *queue) { queue->head = 0; queue->tail = 0; // the current implementation may not fail return SDL_TRUE; } -void control_event_queue_destroy(struct control_event_queue *queue) { +void +control_event_queue_destroy(struct control_event_queue *queue) { int i = queue->tail; while (i != queue->head) { control_event_destroy(&queue->data[i]); @@ -81,7 +88,9 @@ void control_event_queue_destroy(struct control_event_queue *queue) { } } -SDL_bool control_event_queue_push(struct control_event_queue *queue, const struct control_event *event) { +SDL_bool +control_event_queue_push(struct control_event_queue *queue, + const struct control_event *event) { if (control_event_queue_is_full(queue)) { return SDL_FALSE; } @@ -90,7 +99,9 @@ SDL_bool control_event_queue_push(struct control_event_queue *queue, const struc return SDL_TRUE; } -SDL_bool control_event_queue_take(struct control_event_queue *queue, struct control_event *event) { +SDL_bool +control_event_queue_take(struct control_event_queue *queue, + struct control_event *event) { if (control_event_queue_is_empty(queue)) { return SDL_FALSE; } diff --git a/app/src/control_event.h b/app/src/control_event.h index c2569615..18294ef8 100644 --- a/app/src/control_event.h +++ b/app/src/control_event.h @@ -60,18 +60,31 @@ struct control_event_queue { }; // buf size must be at least SERIALIZED_EVENT_MAX_SIZE -int control_event_serialize(const struct control_event *event, unsigned char *buf); +int +control_event_serialize(const struct control_event *event, unsigned char *buf); -SDL_bool control_event_queue_init(struct control_event_queue *queue); -void control_event_queue_destroy(struct control_event_queue *queue); +SDL_bool +control_event_queue_init(struct control_event_queue *queue); -SDL_bool control_event_queue_is_empty(const struct control_event_queue *queue); -SDL_bool control_event_queue_is_full(const struct control_event_queue *queue); +void +control_event_queue_destroy(struct control_event_queue *queue); + +SDL_bool +control_event_queue_is_empty(const struct control_event_queue *queue); + +SDL_bool +control_event_queue_is_full(const struct control_event_queue *queue); // event is copied, the queue does not use the event after the function returns -SDL_bool control_event_queue_push(struct control_event_queue *queue, const struct control_event *event); -SDL_bool control_event_queue_take(struct control_event_queue *queue, struct control_event *event); +SDL_bool +control_event_queue_push(struct control_event_queue *queue, + const struct control_event *event); -void control_event_destroy(struct control_event *event); +SDL_bool +control_event_queue_take(struct control_event_queue *queue, + struct control_event *event); + +void +control_event_destroy(struct control_event *event); #endif diff --git a/app/src/controller.c b/app/src/controller.c index f659d4b9..89be7e98 100644 --- a/app/src/controller.c +++ b/app/src/controller.c @@ -5,7 +5,8 @@ #include "lock_util.h" #include "log.h" -SDL_bool controller_init(struct controller *controller, socket_t video_socket) { +SDL_bool +controller_init(struct controller *controller, socket_t video_socket) { if (!control_event_queue_init(&controller->queue)) { return SDL_FALSE; } @@ -25,13 +26,16 @@ SDL_bool controller_init(struct controller *controller, socket_t video_socket) { return SDL_TRUE; } -void controller_destroy(struct controller *controller) { +void +controller_destroy(struct controller *controller) { SDL_DestroyCond(controller->event_cond); SDL_DestroyMutex(controller->mutex); control_event_queue_destroy(&controller->queue); } -SDL_bool controller_push_event(struct controller *controller, const struct control_event *event) { +SDL_bool +controller_push_event(struct controller *controller, + const struct control_event *event) { SDL_bool res; mutex_lock(controller->mutex); SDL_bool was_empty = control_event_queue_is_empty(&controller->queue); @@ -43,7 +47,9 @@ SDL_bool controller_push_event(struct controller *controller, const struct contr return res; } -static SDL_bool process_event(struct controller *controller, const struct control_event *event) { +static SDL_bool +process_event(struct controller *controller, + const struct control_event *event) { unsigned char serialized_event[SERIALIZED_EVENT_MAX_SIZE]; int length = control_event_serialize(event, serialized_event); if (!length) { @@ -53,12 +59,14 @@ static SDL_bool process_event(struct controller *controller, const struct contro return w == length; } -static int run_controller(void *data) { +static int +run_controller(void *data) { struct controller *controller = data; for (;;) { mutex_lock(controller->mutex); - while (!controller->stopped && control_event_queue_is_empty(&controller->queue)) { + while (!controller->stopped + && control_event_queue_is_empty(&controller->queue)) { cond_wait(controller->event_cond, controller->mutex); } if (controller->stopped) { @@ -67,7 +75,8 @@ static int run_controller(void *data) { break; } struct control_event event; - SDL_bool non_empty = control_event_queue_take(&controller->queue, &event); + SDL_bool non_empty = control_event_queue_take(&controller->queue, + &event); SDL_assert(non_empty); mutex_unlock(controller->mutex); @@ -81,10 +90,12 @@ static int run_controller(void *data) { return 0; } -SDL_bool controller_start(struct controller *controller) { +SDL_bool +controller_start(struct controller *controller) { LOGD("Starting controller thread"); - controller->thread = SDL_CreateThread(run_controller, "controller", controller); + controller->thread = SDL_CreateThread(run_controller, "controller", + controller); if (!controller->thread) { LOGC("Could not start controller thread"); return SDL_FALSE; @@ -93,13 +104,15 @@ SDL_bool controller_start(struct controller *controller) { return SDL_TRUE; } -void controller_stop(struct controller *controller) { +void +controller_stop(struct controller *controller) { mutex_lock(controller->mutex); controller->stopped = SDL_TRUE; cond_signal(controller->event_cond); mutex_unlock(controller->mutex); } -void controller_join(struct controller *controller) { +void +controller_join(struct controller *controller) { SDL_WaitThread(controller->thread, NULL); } diff --git a/app/src/controller.h b/app/src/controller.h index 08d639a6..5afebc82 100644 --- a/app/src/controller.h +++ b/app/src/controller.h @@ -18,14 +18,24 @@ struct controller { struct control_event_queue queue; }; -SDL_bool controller_init(struct controller *controller, socket_t video_socket); -void controller_destroy(struct controller *controller); +SDL_bool +controller_init(struct controller *controller, socket_t video_socket); -SDL_bool controller_start(struct controller *controller); -void controller_stop(struct controller *controller); -void controller_join(struct controller *controller); +void +controller_destroy(struct controller *controller); + +SDL_bool +controller_start(struct controller *controller); + +void +controller_stop(struct controller *controller); + +void +controller_join(struct controller *controller); // expose simple API to hide control_event_queue -SDL_bool controller_push_event(struct controller *controller, const struct control_event *event); +SDL_bool +controller_push_event(struct controller *controller, + const struct control_event *event); #endif diff --git a/app/src/convert.c b/app/src/convert.c index 7d40b938..6bdd9631 100644 --- a/app/src/convert.c +++ b/app/src/convert.c @@ -3,7 +3,8 @@ #define MAP(FROM, TO) case FROM: *to = TO; return SDL_TRUE #define FAIL default: return SDL_FALSE -static SDL_bool convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to) { +static SDL_bool +convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to) { switch (from) { MAP(SDL_KEYDOWN, AKEY_EVENT_ACTION_DOWN); MAP(SDL_KEYUP, AKEY_EVENT_ACTION_UP); @@ -11,7 +12,8 @@ static SDL_bool convert_keycode_action(SDL_EventType from, enum android_keyevent } } -static enum android_metastate autocomplete_metastate(enum android_metastate metastate) { +static enum android_metastate +autocomplete_metastate(enum android_metastate metastate) { // fill dependant flags if (metastate & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { metastate |= AMETA_SHIFT_ON; @@ -30,7 +32,8 @@ static enum android_metastate autocomplete_metastate(enum android_metastate meta } -static enum android_metastate convert_meta_state(SDL_Keymod mod) { +static enum android_metastate +convert_meta_state(SDL_Keymod mod) { enum android_metastate metastate = 0; if (mod & KMOD_LSHIFT) { metastate |= AMETA_SHIFT_LEFT_ON; @@ -70,7 +73,8 @@ static enum android_metastate convert_meta_state(SDL_Keymod mod) { return autocomplete_metastate(metastate); } -static SDL_bool convert_keycode(SDL_Keycode from, enum android_keycode *to, Uint16 mod) { +static SDL_bool +convert_keycode(SDL_Keycode from, enum android_keycode *to, Uint16 mod) { switch (from) { MAP(SDLK_RETURN, AKEYCODE_ENTER); MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER); @@ -123,7 +127,8 @@ static SDL_bool convert_keycode(SDL_Keycode from, enum android_keycode *to, Uint } } -static SDL_bool convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) { +static SDL_bool +convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) { switch (from) { MAP(SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN); MAP(SDL_MOUSEBUTTONUP, AMOTION_EVENT_ACTION_UP); @@ -131,7 +136,8 @@ static SDL_bool convert_mouse_action(SDL_EventType from, enum android_motioneven } } -static enum android_motionevent_buttons convert_mouse_buttons(Uint32 state) { +static enum android_motionevent_buttons +convert_mouse_buttons(Uint32 state) { enum android_motionevent_buttons buttons = 0; if (state & SDL_BUTTON_LMASK) { buttons |= AMOTION_EVENT_BUTTON_PRIMARY; @@ -151,8 +157,9 @@ static enum android_motionevent_buttons convert_mouse_buttons(Uint32 state) { return buttons; } -SDL_bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from, - struct control_event *to) { +SDL_bool +input_key_from_sdl_to_android(const SDL_KeyboardEvent *from, + struct control_event *to) { to->type = CONTROL_EVENT_TYPE_KEYCODE; if (!convert_keycode_action(from->type, &to->keycode_event.action)) { @@ -169,9 +176,10 @@ SDL_bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from, return SDL_TRUE; } -SDL_bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, - struct size screen_size, - struct control_event *to) { +SDL_bool +mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, + struct size screen_size, + struct control_event *to) { to->type = CONTROL_EVENT_TYPE_MOUSE; if (!convert_mouse_action(from->type, &to->mouse_event.action)) { @@ -186,9 +194,10 @@ SDL_bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, return SDL_TRUE; } -SDL_bool mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, - struct size screen_size, - struct control_event *to) { +SDL_bool +mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, + struct size screen_size, + struct control_event *to) { to->type = CONTROL_EVENT_TYPE_MOUSE; to->mouse_event.action = AMOTION_EVENT_ACTION_MOVE; to->mouse_event.buttons = convert_mouse_buttons(from->state); @@ -199,9 +208,10 @@ SDL_bool mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, return SDL_TRUE; } -SDL_bool mouse_wheel_from_sdl_to_android(const SDL_MouseWheelEvent *from, - struct position position, - struct control_event *to) { +SDL_bool +mouse_wheel_from_sdl_to_android(const SDL_MouseWheelEvent *from, + struct position position, + struct control_event *to) { to->type = CONTROL_EVENT_TYPE_SCROLL; to->scroll_event.position = position; diff --git a/app/src/convert.h b/app/src/convert.h index 30f0dd3d..edd3e0fa 100644 --- a/app/src/convert.h +++ b/app/src/convert.h @@ -15,21 +15,26 @@ struct complete_mouse_wheel_event { struct point position; }; -SDL_bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from, - struct control_event *to); -SDL_bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, - struct size screen_size, - struct control_event *to); +SDL_bool +input_key_from_sdl_to_android(const SDL_KeyboardEvent *from, + struct control_event *to); -// the video size may be different from the real device size, so we need the size -// to which the absolute position apply, to scale it accordingly -SDL_bool mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, - struct size screen_size, - struct control_event *to); +SDL_bool +mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, + struct size screen_size, + struct control_event *to); + +// the video size may be different from the real device size, so we need the +// size to which the absolute position apply, to scale it accordingly +SDL_bool +mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, + struct size screen_size, + struct control_event *to); // on Android, a scroll event requires the current mouse position -SDL_bool mouse_wheel_from_sdl_to_android(const SDL_MouseWheelEvent *from, - struct position position, - struct control_event *to); +SDL_bool +mouse_wheel_from_sdl_to_android(const SDL_MouseWheelEvent *from, + struct position position, + struct control_event *to); #endif diff --git a/app/src/decoder.c b/app/src/decoder.c index ef375fad..84886c9d 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -18,8 +18,10 @@ #include "video_buffer.h" // set the decoded frame as ready for rendering, and notify -static void push_frame(struct decoder *decoder) { - SDL_bool previous_frame_consumed = video_buffer_offer_decoded_frame(decoder->video_buffer); +static void +push_frame(struct decoder *decoder) { + SDL_bool previous_frame_consumed = + video_buffer_offer_decoded_frame(decoder->video_buffer); if (!previous_frame_consumed) { // the previous EVENT_NEW_FRAME will consume this frame return; @@ -30,11 +32,13 @@ static void push_frame(struct decoder *decoder) { SDL_PushEvent(&new_frame_event); } -void decoder_init(struct decoder *decoder, struct video_buffer *vb) { +void +decoder_init(struct decoder *decoder, struct video_buffer *vb) { decoder->video_buffer = vb; } -SDL_bool decoder_open(struct decoder *decoder, AVCodec *codec) { +SDL_bool +decoder_open(struct decoder *decoder, AVCodec *codec) { decoder->codec_ctx = avcodec_alloc_context3(codec); if (!decoder->codec_ctx) { LOGC("Could not allocate decoder context"); @@ -50,12 +54,14 @@ SDL_bool decoder_open(struct decoder *decoder, AVCodec *codec) { return SDL_TRUE; } -void decoder_close(struct decoder *decoder) { +void +decoder_close(struct decoder *decoder) { avcodec_close(decoder->codec_ctx); avcodec_free_context(&decoder->codec_ctx); } -SDL_bool decoder_push(struct decoder *decoder, AVPacket *packet) { +SDL_bool +decoder_push(struct decoder *decoder, AVPacket *packet) { // the new decoding/encoding API has been introduced by: // #ifdef SCRCPY_LAVF_HAS_NEW_ENCODING_DECODING_API @@ -90,6 +96,7 @@ SDL_bool decoder_push(struct decoder *decoder, AVPacket *packet) { return SDL_TRUE; } -void decoder_interrupt(struct decoder *decoder) { +void +decoder_interrupt(struct decoder *decoder) { video_buffer_interrupt(decoder->video_buffer); } diff --git a/app/src/decoder.h b/app/src/decoder.h index ac8308c7..266876c9 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -11,12 +11,19 @@ struct decoder { AVCodecContext *codec_ctx; }; -void decoder_init(struct decoder *decoder, struct video_buffer *vb); +void +decoder_init(struct decoder *decoder, struct video_buffer *vb); -SDL_bool decoder_open(struct decoder *decoder, AVCodec *codec); -void decoder_close(struct decoder *decoder); +SDL_bool +decoder_open(struct decoder *decoder, AVCodec *codec); -SDL_bool decoder_push(struct decoder *decoder, AVPacket *packet); -void decoder_interrupt(struct decoder *decoder); +void +decoder_close(struct decoder *decoder); + +SDL_bool +decoder_push(struct decoder *decoder, AVPacket *packet); + +void +decoder_interrupt(struct decoder *decoder); #endif diff --git a/app/src/device.c b/app/src/device.c index 1e5ea625..9c38bf12 100644 --- a/app/src/device.c +++ b/app/src/device.c @@ -1,18 +1,22 @@ #include "device.h" #include "log.h" -SDL_bool device_read_info(socket_t device_socket, char *device_name, struct size *size) { +SDL_bool +device_read_info(socket_t device_socket, char *device_name, struct size *size) { unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4]; int r = net_recv_all(device_socket, buf, sizeof(buf)); if (r < DEVICE_NAME_FIELD_LENGTH + 4) { LOGE("Could not retrieve device information"); return SDL_FALSE; } - buf[DEVICE_NAME_FIELD_LENGTH - 1] = '\0'; // in case the client sends garbage - // strcpy is safe here, since name contains at least DEVICE_NAME_FIELD_LENGTH bytes - // and strlen(buf) < DEVICE_NAME_FIELD_LENGTH + // in case the client sends garbage + buf[DEVICE_NAME_FIELD_LENGTH - 1] = '\0'; + // strcpy is safe here, since name contains at least + // DEVICE_NAME_FIELD_LENGTH bytes and strlen(buf) < DEVICE_NAME_FIELD_LENGTH strcpy(device_name, (char *) buf); - size->width = (buf[DEVICE_NAME_FIELD_LENGTH] << 8) | buf[DEVICE_NAME_FIELD_LENGTH + 1]; - size->height = (buf[DEVICE_NAME_FIELD_LENGTH + 2] << 8) | buf[DEVICE_NAME_FIELD_LENGTH + 3]; + size->width = (buf[DEVICE_NAME_FIELD_LENGTH] << 8) + | buf[DEVICE_NAME_FIELD_LENGTH + 1]; + size->height = (buf[DEVICE_NAME_FIELD_LENGTH + 2] << 8) + | buf[DEVICE_NAME_FIELD_LENGTH + 3]; return SDL_TRUE; } diff --git a/app/src/device.h b/app/src/device.h index 125dda3a..bacc5355 100644 --- a/app/src/device.h +++ b/app/src/device.h @@ -10,6 +10,7 @@ #define DEVICE_SDCARD_PATH "/sdcard/" // name must be at least DEVICE_NAME_FIELD_LENGTH bytes -SDL_bool device_read_info(socket_t device_socket, char *name, struct size *frame_size); +SDL_bool +device_read_info(socket_t device_socket, char *name, struct size *frame_size); #endif diff --git a/app/src/file_handler.c b/app/src/file_handler.c index d1e0fd7b..f70f61d3 100644 --- a/app/src/file_handler.c +++ b/app/src/file_handler.c @@ -13,7 +13,8 @@ struct request { const char *file; }; -static struct request *request_new(file_handler_action_t action, const char *file) { +static struct request * +request_new(file_handler_action_t action, const char *file) { struct request *req = SDL_malloc(sizeof(*req)); if (!req) { return NULL; @@ -23,7 +24,8 @@ static struct request *request_new(file_handler_action_t action, const char *fil return req; } -static void request_free(struct request *req) { +static void +request_free(struct request *req) { if (!req) { return; } @@ -31,21 +33,25 @@ static void request_free(struct request *req) { SDL_free((void *) req); } -static SDL_bool request_queue_is_empty(const struct request_queue *queue) { +static SDL_bool +request_queue_is_empty(const struct request_queue *queue) { return queue->head == queue->tail; } -static SDL_bool request_queue_is_full(const struct request_queue *queue) { +static SDL_bool +request_queue_is_full(const struct request_queue *queue) { return (queue->head + 1) % REQUEST_QUEUE_SIZE == queue->tail; } -static SDL_bool request_queue_init(struct request_queue *queue) { +static SDL_bool +request_queue_init(struct request_queue *queue) { queue->head = 0; queue->tail = 0; return SDL_TRUE; } -static void request_queue_destroy(struct request_queue *queue) { +static void +request_queue_destroy(struct request_queue *queue) { int i = queue->tail; while (i != queue->head) { request_free(queue->reqs[i]); @@ -53,7 +59,8 @@ static void request_queue_destroy(struct request_queue *queue) { } } -static SDL_bool request_queue_push(struct request_queue *queue, struct request *req) { +static SDL_bool +request_queue_push(struct request_queue *queue, struct request *req) { if (request_queue_is_full(queue)) { return SDL_FALSE; } @@ -62,7 +69,8 @@ static SDL_bool request_queue_push(struct request_queue *queue, struct request * return SDL_TRUE; } -static SDL_bool request_queue_take(struct request_queue *queue, struct request **req) { +static SDL_bool +request_queue_take(struct request_queue *queue, struct request **req) { if (request_queue_is_empty(queue)) { return SDL_FALSE; } @@ -72,7 +80,8 @@ static SDL_bool request_queue_take(struct request_queue *queue, struct request * return SDL_TRUE; } -SDL_bool file_handler_init(struct file_handler *file_handler, const char *serial) { +SDL_bool +file_handler_init(struct file_handler *file_handler, const char *serial) { if (!request_queue_init(&file_handler->queue)) { return SDL_FALSE; @@ -107,24 +116,28 @@ SDL_bool file_handler_init(struct file_handler *file_handler, const char *serial return SDL_TRUE; } -void file_handler_destroy(struct file_handler *file_handler) { +void +file_handler_destroy(struct file_handler *file_handler) { SDL_DestroyCond(file_handler->event_cond); SDL_DestroyMutex(file_handler->mutex); request_queue_destroy(&file_handler->queue); SDL_free((void *) file_handler->serial); } -static process_t install_apk(const char *serial, const char *file) { +static process_t +install_apk(const char *serial, const char *file) { return adb_install(serial, file); } -static process_t push_file(const char *serial, const char *file) { +static process_t +push_file(const char *serial, const char *file) { return adb_push(serial, file, DEVICE_SDCARD_PATH); } -SDL_bool file_handler_request(struct file_handler *file_handler, - file_handler_action_t action, - const char *file) { +SDL_bool +file_handler_request(struct file_handler *file_handler, + file_handler_action_t action, + const char *file) { SDL_bool res; // start file_handler if it's used for the first time @@ -135,7 +148,8 @@ SDL_bool file_handler_request(struct file_handler *file_handler, file_handler->initialized = SDL_TRUE; } - LOGI("Request to %s %s", action == ACTION_INSTALL_APK ? "install" : "push", file); + LOGI("Request to %s %s", action == ACTION_INSTALL_APK ? "install" : "push", + file); struct request *req = request_new(action, file); if (!req) { LOGE("Could not create request"); @@ -152,13 +166,15 @@ SDL_bool file_handler_request(struct file_handler *file_handler, return res; } -static int run_file_handler(void *data) { +static int +run_file_handler(void *data) { struct file_handler *file_handler = data; for (;;) { mutex_lock(file_handler->mutex); file_handler->current_process = PROCESS_NONE; - while (!file_handler->stopped && request_queue_is_empty(&file_handler->queue)) { + while (!file_handler->stopped + && request_queue_is_empty(&file_handler->queue)) { cond_wait(file_handler->event_cond, file_handler->mutex); } if (file_handler->stopped) { @@ -200,10 +216,12 @@ static int run_file_handler(void *data) { return 0; } -SDL_bool file_handler_start(struct file_handler *file_handler) { +SDL_bool +file_handler_start(struct file_handler *file_handler) { LOGD("Starting file_handler thread"); - file_handler->thread = SDL_CreateThread(run_file_handler, "file_handler", file_handler); + file_handler->thread = SDL_CreateThread(run_file_handler, "file_handler", + file_handler); if (!file_handler->thread) { LOGC("Could not start file_handler thread"); return SDL_FALSE; @@ -212,7 +230,8 @@ SDL_bool file_handler_start(struct file_handler *file_handler) { return SDL_TRUE; } -void file_handler_stop(struct file_handler *file_handler) { +void +file_handler_stop(struct file_handler *file_handler) { mutex_lock(file_handler->mutex); file_handler->stopped = SDL_TRUE; cond_signal(file_handler->event_cond); @@ -226,6 +245,7 @@ void file_handler_stop(struct file_handler *file_handler) { mutex_unlock(file_handler->mutex); } -void file_handler_join(struct file_handler *file_handler) { +void +file_handler_join(struct file_handler *file_handler) { SDL_WaitThread(file_handler->thread, NULL); } diff --git a/app/src/file_handler.h b/app/src/file_handler.h index 9ce39367..ed1c8867 100644 --- a/app/src/file_handler.h +++ b/app/src/file_handler.h @@ -30,15 +30,24 @@ struct file_handler { struct request_queue queue; }; -SDL_bool file_handler_init(struct file_handler *file_handler, const char *serial); -void file_handler_destroy(struct file_handler *file_handler); +SDL_bool +file_handler_init(struct file_handler *file_handler, const char *serial); -SDL_bool file_handler_start(struct file_handler *file_handler); -void file_handler_stop(struct file_handler *file_handler); -void file_handler_join(struct file_handler *file_handler); +void +file_handler_destroy(struct file_handler *file_handler); -SDL_bool file_handler_request(struct file_handler *file_handler, - file_handler_action_t action, - const char *file); +SDL_bool +file_handler_start(struct file_handler *file_handler); + +void +file_handler_stop(struct file_handler *file_handler); + +void +file_handler_join(struct file_handler *file_handler); + +SDL_bool +file_handler_request(struct file_handler *file_handler, + file_handler_action_t action, + const char *file); #endif diff --git a/app/src/fps_counter.c b/app/src/fps_counter.c index 27aa4ee0..fc86f22c 100644 --- a/app/src/fps_counter.c +++ b/app/src/fps_counter.c @@ -4,13 +4,15 @@ #include "log.h" -void fps_counter_init(struct fps_counter *counter) { +void +fps_counter_init(struct fps_counter *counter) { counter->started = SDL_FALSE; // no need to initialize the other fields, they are meaningful only when // started is true } -void fps_counter_start(struct fps_counter *counter) { +void +fps_counter_start(struct fps_counter *counter) { counter->started = SDL_TRUE; counter->slice_start = SDL_GetTicks(); counter->nr_rendered = 0; @@ -19,14 +21,17 @@ void fps_counter_start(struct fps_counter *counter) { #endif } -void fps_counter_stop(struct fps_counter *counter) { +void +fps_counter_stop(struct fps_counter *counter) { counter->started = SDL_FALSE; } -static void display_fps(struct fps_counter *counter) { +static void +display_fps(struct fps_counter *counter) { #ifdef SKIP_FRAMES if (counter->nr_skipped) { - LOGI("%d fps (+%d frames skipped)", counter->nr_rendered, counter->nr_skipped); + LOGI("%d fps (+%d frames skipped)", counter->nr_rendered, + counter->nr_skipped); } else { #endif LOGI("%d fps", counter->nr_rendered); @@ -35,7 +40,8 @@ static void display_fps(struct fps_counter *counter) { #endif } -static void check_expired(struct fps_counter *counter) { +static void +check_expired(struct fps_counter *counter) { Uint32 now = SDL_GetTicks(); if (now - counter->slice_start >= 1000) { display_fps(counter); @@ -49,13 +55,15 @@ static void check_expired(struct fps_counter *counter) { } } -void fps_counter_add_rendered_frame(struct fps_counter *counter) { +void +fps_counter_add_rendered_frame(struct fps_counter *counter) { check_expired(counter); ++counter->nr_rendered; } #ifdef SKIP_FRAMES -void fps_counter_add_skipped_frame(struct fps_counter *counter) { +void +fps_counter_add_skipped_frame(struct fps_counter *counter) { check_expired(counter); ++counter->nr_skipped; } diff --git a/app/src/fps_counter.h b/app/src/fps_counter.h index 27b16f28..2d48624f 100644 --- a/app/src/fps_counter.h +++ b/app/src/fps_counter.h @@ -14,13 +14,21 @@ struct fps_counter { #endif }; -void fps_counter_init(struct fps_counter *counter); -void fps_counter_start(struct fps_counter *counter); -void fps_counter_stop(struct fps_counter *counter); +void +fps_counter_init(struct fps_counter *counter); + +void +fps_counter_start(struct fps_counter *counter); + +void +fps_counter_stop(struct fps_counter *counter); + +void +fps_counter_add_rendered_frame(struct fps_counter *counter); -void fps_counter_add_rendered_frame(struct fps_counter *counter); #ifdef SKIP_FRAMES -void fps_counter_add_skipped_frame(struct fps_counter *counter); +void +fps_counter_add_skipped_frame(struct fps_counter *counter); #endif #endif diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 35e029f0..f76618d0 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -5,11 +5,13 @@ #include "lock_util.h" #include "log.h" -// Convert window coordinates (as provided by SDL_GetMouseState() to renderer coordinates (as provided in SDL mouse events) +// Convert window coordinates (as provided by SDL_GetMouseState() to renderer +// coordinates (as provided in SDL mouse events) // // See my question: // -static void convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int *y) { +static void +convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int *y) { SDL_Rect viewport; float scale_x, scale_y; SDL_RenderGetViewport(renderer, &viewport); @@ -18,7 +20,8 @@ static void convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int *y = (int) (*y / scale_y) - viewport.y; } -static struct point get_mouse_point(struct screen *screen) { +static struct point +get_mouse_point(struct screen *screen) { int x; int y; SDL_GetMouseState(&x, &y); @@ -32,7 +35,9 @@ static struct point get_mouse_point(struct screen *screen) { static const int ACTION_DOWN = 1; static const int ACTION_UP = 1 << 1; -static void send_keycode(struct controller *controller, enum android_keycode keycode, int actions, const char *name) { +static void +send_keycode(struct controller *controller, enum android_keycode keycode, + int actions, const char *name) { // send DOWN event struct control_event control_event; control_event.type = CONTROL_EVENT_TYPE_KEYCODE; @@ -55,66 +60,80 @@ static void send_keycode(struct controller *controller, enum android_keycode key } } -static inline void action_home(struct controller *controller, int actions) { +static inline void +action_home(struct controller *controller, int actions) { send_keycode(controller, AKEYCODE_HOME, actions, "HOME"); } -static inline void action_back(struct controller *controller, int actions) { +static inline void +action_back(struct controller *controller, int actions) { send_keycode(controller, AKEYCODE_BACK, actions, "BACK"); } -static inline void action_app_switch(struct controller *controller, int actions) { +static inline void +action_app_switch(struct controller *controller, int actions) { send_keycode(controller, AKEYCODE_APP_SWITCH, actions, "APP_SWITCH"); } -static inline void action_power(struct controller *controller, int actions) { +static inline void +action_power(struct controller *controller, int actions) { send_keycode(controller, AKEYCODE_POWER, actions, "POWER"); } -static inline void action_volume_up(struct controller *controller, int actions) { +static inline void +action_volume_up(struct controller *controller, int actions) { send_keycode(controller, AKEYCODE_VOLUME_UP, actions, "VOLUME_UP"); } -static inline void action_volume_down(struct controller *controller, int actions) { +static inline void +action_volume_down(struct controller *controller, int actions) { send_keycode(controller, AKEYCODE_VOLUME_DOWN, actions, "VOLUME_DOWN"); } -static inline void action_menu(struct controller *controller, int actions) { +static inline void +action_menu(struct controller *controller, int actions) { send_keycode(controller, AKEYCODE_MENU, actions, "MENU"); } // turn the screen on if it was off, press BACK otherwise -static void press_back_or_turn_screen_on(struct controller *controller) { +static void +press_back_or_turn_screen_on(struct controller *controller) { struct control_event control_event; control_event.type = CONTROL_EVENT_TYPE_COMMAND; - control_event.command_event.action = CONTROL_EVENT_COMMAND_BACK_OR_SCREEN_ON; + control_event.command_event.action = + CONTROL_EVENT_COMMAND_BACK_OR_SCREEN_ON; if (!controller_push_event(controller, &control_event)) { LOGW("Cannot turn screen on"); } } -static void expand_notification_panel(struct controller *controller) { +static void +expand_notification_panel(struct controller *controller) { struct control_event control_event; control_event.type = CONTROL_EVENT_TYPE_COMMAND; - control_event.command_event.action = CONTROL_EVENT_COMMAND_EXPAND_NOTIFICATION_PANEL; + control_event.command_event.action = + CONTROL_EVENT_COMMAND_EXPAND_NOTIFICATION_PANEL; if (!controller_push_event(controller, &control_event)) { LOGW("Cannot expand notification panel"); } } -static void collapse_notification_panel(struct controller *controller) { +static void +collapse_notification_panel(struct controller *controller) { struct control_event control_event; control_event.type = CONTROL_EVENT_TYPE_COMMAND; - control_event.command_event.action = CONTROL_EVENT_COMMAND_COLLAPSE_NOTIFICATION_PANEL; + control_event.command_event.action = + CONTROL_EVENT_COMMAND_COLLAPSE_NOTIFICATION_PANEL; if (!controller_push_event(controller, &control_event)) { LOGW("Cannot collapse notification panel"); } } -static void switch_fps_counter_state(struct video_buffer *vb) { +static void +switch_fps_counter_state(struct video_buffer *vb) { mutex_lock(vb->mutex); if (vb->fps_counter.started) { LOGI("FPS counter stopped"); @@ -126,7 +145,8 @@ static void switch_fps_counter_state(struct video_buffer *vb) { mutex_unlock(vb->mutex); } -static void clipboard_paste(struct controller *controller) { +static void +clipboard_paste(struct controller *controller) { char *text = SDL_GetClipboardText(); if (!text) { LOGW("Cannot get clipboard text: %s", SDL_GetError()); @@ -147,8 +167,9 @@ static void clipboard_paste(struct controller *controller) { } } -void input_manager_process_text_input(struct input_manager *input_manager, - const SDL_TextInputEvent *event) { +void +input_manager_process_text_input(struct input_manager *input_manager, + const SDL_TextInputEvent *event) { char c = event->text[0]; if (isalpha(c) || c == ' ') { SDL_assert(event->text[1] == '\0'); @@ -168,8 +189,9 @@ void input_manager_process_text_input(struct input_manager *input_manager, } } -void input_manager_process_key(struct input_manager *input_manager, - const SDL_KeyboardEvent *event) { +void +input_manager_process_key(struct input_manager *input_manager, + const SDL_KeyboardEvent *event) { SDL_bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL); SDL_bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT); SDL_bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI); @@ -285,29 +307,33 @@ void input_manager_process_key(struct input_manager *input_manager, } } -void input_manager_process_mouse_motion(struct input_manager *input_manager, - const SDL_MouseMotionEvent *event) { +void +input_manager_process_mouse_motion(struct input_manager *input_manager, + const SDL_MouseMotionEvent *event) { if (!event->state) { // do not send motion events when no button is pressed return; } struct control_event control_event; - if (mouse_motion_from_sdl_to_android(event, input_manager->screen->frame_size, &control_event)) { + if (mouse_motion_from_sdl_to_android(event, + input_manager->screen->frame_size, + &control_event)) { if (!controller_push_event(input_manager->controller, &control_event)) { LOGW("Cannot send mouse motion event"); } } } -static SDL_bool is_outside_device_screen(struct input_manager *input_manager, - int x, int y) +static SDL_bool +is_outside_device_screen(struct input_manager *input_manager, int x, int y) { return x < 0 || x >= input_manager->screen->frame_size.width || y < 0 || y >= input_manager->screen->frame_size.height; } -void input_manager_process_mouse_button(struct input_manager *input_manager, - const SDL_MouseButtonEvent *event) { +void +input_manager_process_mouse_button(struct input_manager *input_manager, + const SDL_MouseButtonEvent *event) { if (event->type == SDL_MOUSEBUTTONDOWN) { if (event->button == SDL_BUTTON_RIGHT) { press_back_or_turn_screen_on(input_manager->controller); @@ -331,15 +357,18 @@ void input_manager_process_mouse_button(struct input_manager *input_manager, } struct control_event control_event; - if (mouse_button_from_sdl_to_android(event, input_manager->screen->frame_size, &control_event)) { + if (mouse_button_from_sdl_to_android(event, + input_manager->screen->frame_size, + &control_event)) { if (!controller_push_event(input_manager->controller, &control_event)) { LOGW("Cannot send mouse button event"); } } } -void input_manager_process_mouse_wheel(struct input_manager *input_manager, - const SDL_MouseWheelEvent *event) { +void +input_manager_process_mouse_wheel(struct input_manager *input_manager, + const SDL_MouseWheelEvent *event) { struct position position = { .screen_size = input_manager->screen->frame_size, .point = get_mouse_point(input_manager->screen), diff --git a/app/src/input_manager.h b/app/src/input_manager.h index 7aed1793..62923e1e 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -13,15 +13,24 @@ struct input_manager { struct screen *screen; }; -void input_manager_process_text_input(struct input_manager *input_manager, - const SDL_TextInputEvent *event); -void input_manager_process_key(struct input_manager *input_manager, - const SDL_KeyboardEvent *event); -void input_manager_process_mouse_motion(struct input_manager *input_manager, - const SDL_MouseMotionEvent *event); -void input_manager_process_mouse_button(struct input_manager *input_manager, - const SDL_MouseButtonEvent *event); -void input_manager_process_mouse_wheel(struct input_manager *input_manager, - const SDL_MouseWheelEvent *event); +void +input_manager_process_text_input(struct input_manager *input_manager, + const SDL_TextInputEvent *event); + +void +input_manager_process_key(struct input_manager *input_manager, + const SDL_KeyboardEvent *event); + +void +input_manager_process_mouse_motion(struct input_manager *input_manager, + const SDL_MouseMotionEvent *event); + +void +input_manager_process_mouse_button(struct input_manager *input_manager, + const SDL_MouseButtonEvent *event); + +void +input_manager_process_mouse_wheel(struct input_manager *input_manager, + const SDL_MouseWheelEvent *event); #endif diff --git a/app/src/lock_util.c b/app/src/lock_util.c index 723d3b13..7b70ba6b 100644 --- a/app/src/lock_util.c +++ b/app/src/lock_util.c @@ -4,28 +4,32 @@ #include "log.h" -void mutex_lock(SDL_mutex *mutex) { +void +mutex_lock(SDL_mutex *mutex) { if (SDL_LockMutex(mutex)) { LOGC("Could not lock mutex"); abort(); } } -void mutex_unlock(SDL_mutex *mutex) { +void +mutex_unlock(SDL_mutex *mutex) { if (SDL_UnlockMutex(mutex)) { LOGC("Could not unlock mutex"); abort(); } } -void cond_wait(SDL_cond *cond, SDL_mutex *mutex) { +void +cond_wait(SDL_cond *cond, SDL_mutex *mutex) { if (SDL_CondWait(cond, mutex)) { LOGC("Could not wait on condition"); abort(); } } -void cond_signal(SDL_cond *cond) { +void +cond_signal(SDL_cond *cond) { if (SDL_CondSignal(cond)) { LOGC("Could not signal a condition"); abort(); diff --git a/app/src/lock_util.h b/app/src/lock_util.h index 255cafe4..99c1f8d6 100644 --- a/app/src/lock_util.h +++ b/app/src/lock_util.h @@ -5,9 +5,16 @@ typedef struct SDL_mutex SDL_mutex; typedef struct SDL_cond SDL_cond; -void mutex_lock(SDL_mutex *mutex); -void mutex_unlock(SDL_mutex *mutex); -void cond_wait(SDL_cond *cond, SDL_mutex *mutex); -void cond_signal(SDL_cond *cond); +void +mutex_lock(SDL_mutex *mutex); + +void +mutex_unlock(SDL_mutex *mutex); + +void +cond_wait(SDL_cond *cond, SDL_mutex *mutex); + +void +cond_signal(SDL_cond *cond); #endif diff --git a/app/src/main.c b/app/src/main.c index c4ffad24..92b1507a 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -145,17 +145,26 @@ static void usage(const char *arg0) { DEFAULT_LOCAL_PORT); } -static void print_version(void) { +static void +print_version(void) { fprintf(stderr, "scrcpy %s\n\n", SCRCPY_VERSION); fprintf(stderr, "dependencies:\n"); - fprintf(stderr, " - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL); - fprintf(stderr, " - libavcodec %d.%d.%d\n", LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO); - fprintf(stderr, " - libavformat %d.%d.%d\n", LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO); - fprintf(stderr, " - libavutil %d.%d.%d\n", LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO); + fprintf(stderr, " - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, + SDL_PATCHLEVEL); + fprintf(stderr, " - libavcodec %d.%d.%d\n", LIBAVCODEC_VERSION_MAJOR, + LIBAVCODEC_VERSION_MINOR, + LIBAVCODEC_VERSION_MICRO); + fprintf(stderr, " - libavformat %d.%d.%d\n", LIBAVFORMAT_VERSION_MAJOR, + LIBAVFORMAT_VERSION_MINOR, + LIBAVFORMAT_VERSION_MICRO); + fprintf(stderr, " - libavutil %d.%d.%d\n", LIBAVUTIL_VERSION_MAJOR, + LIBAVUTIL_VERSION_MINOR, + LIBAVUTIL_VERSION_MICRO); } -static SDL_bool parse_bit_rate(char *optarg, Uint32 *bit_rate) { +static SDL_bool +parse_bit_rate(char *optarg, Uint32 *bit_rate) { char *endptr; if (*optarg == '\0') { LOGE("Bit-rate parameter is empty"); @@ -186,7 +195,8 @@ static SDL_bool parse_bit_rate(char *optarg, Uint32 *bit_rate) { return SDL_TRUE; } -static SDL_bool parse_max_size(char *optarg, Uint16 *max_size) { +static SDL_bool +parse_max_size(char *optarg, Uint16 *max_size) { char *endptr; if (*optarg == '\0') { LOGE("Max size parameter is empty"); @@ -206,7 +216,8 @@ static SDL_bool parse_max_size(char *optarg, Uint16 *max_size) { return SDL_TRUE; } -static SDL_bool parse_port(char *optarg, Uint16 *port) { +static SDL_bool +parse_port(char *optarg, Uint16 *port) { char *endptr; if (*optarg == '\0') { LOGE("Invalid port parameter is empty"); @@ -256,7 +267,8 @@ guess_record_format(const char *filename) { return 0; } -static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { +static SDL_bool +parse_args(struct args *args, int argc, char *argv[]) { static const struct option long_options[] = { {"always-on-top", no_argument, NULL, 'T'}, {"bit-rate", required_argument, NULL, 'b'}, @@ -274,7 +286,8 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { {NULL, 0, NULL, 0 }, }; int c; - while ((c = getopt_long(argc, argv, "b:c:fF:hm:np:r:s:tTv", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "b:c:fF:hm:np:r:s:tTv", long_options, + NULL)) != -1) { switch (c) { case 'b': if (!parse_bit_rate(optarg, &args->bit_rate)) { @@ -362,7 +375,8 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) { return SDL_TRUE; } -int main(int argc, char *argv[]) { +int +main(int argc, char *argv[]) { #ifdef __WINDOWS__ // disable buffering, we want logs immediately // even line buffering (setvbuf() with mode _IOLBF) is not sufficient diff --git a/app/src/net.c b/app/src/net.c index ba9a7776..70fcb304 100644 --- a/app/src/net.c +++ b/app/src/net.c @@ -18,7 +18,8 @@ typedef struct in_addr IN_ADDR; #endif -socket_t net_connect(Uint32 addr, Uint16 port) { +socket_t +net_connect(Uint32 addr, Uint16 port) { socket_t sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { perror("socket"); @@ -38,7 +39,8 @@ socket_t net_connect(Uint32 addr, Uint16 port) { return sock; } -socket_t net_listen(Uint32 addr, Uint16 port, int backlog) { +socket_t +net_listen(Uint32 addr, Uint16 port, int backlog) { socket_t sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { perror("socket"); @@ -46,7 +48,8 @@ socket_t net_listen(Uint32 addr, Uint16 port, int backlog) { } int reuse = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(reuse)) == -1) { + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, + sizeof(reuse)) == -1) { perror("setsockopt(SO_REUSEADDR)"); } @@ -68,25 +71,30 @@ socket_t net_listen(Uint32 addr, Uint16 port, int backlog) { return sock; } -socket_t net_accept(socket_t server_socket) { +socket_t +net_accept(socket_t server_socket) { SOCKADDR_IN csin; socklen_t sinsize = sizeof(csin); return accept(server_socket, (SOCKADDR *) &csin, &sinsize); } -ssize_t net_recv(socket_t socket, void *buf, size_t len) { +ssize_t +net_recv(socket_t socket, void *buf, size_t len) { return recv(socket, buf, len, 0); } -ssize_t net_recv_all(socket_t socket, void *buf, size_t len) { +ssize_t +net_recv_all(socket_t socket, void *buf, size_t len) { return recv(socket, buf, len, MSG_WAITALL); } -ssize_t net_send(socket_t socket, const void *buf, size_t len) { +ssize_t +net_send(socket_t socket, const void *buf, size_t len) { return send(socket, buf, len, 0); } -ssize_t net_send_all(socket_t socket, const void *buf, size_t len) { +ssize_t +net_send_all(socket_t socket, const void *buf, size_t len) { ssize_t w = 0; while (len > 0) { w = send(socket, buf, len, 0); @@ -99,6 +107,7 @@ ssize_t net_send_all(socket_t socket, const void *buf, size_t len) { return w; } -SDL_bool net_shutdown(socket_t socket, int how) { +SDL_bool +net_shutdown(socket_t socket, int how) { return !shutdown(socket, how); } diff --git a/app/src/net.h b/app/src/net.h index 1be1e815..d712e6d3 100644 --- a/app/src/net.h +++ b/app/src/net.h @@ -16,20 +16,39 @@ typedef int socket_t; #endif -SDL_bool net_init(void); -void net_cleanup(void); +SDL_bool +net_init(void); -socket_t net_connect(Uint32 addr, Uint16 port); -socket_t net_listen(Uint32 addr, Uint16 port, int backlog); -socket_t net_accept(socket_t server_socket); +void +net_cleanup(void); + +socket_t +net_connect(Uint32 addr, Uint16 port); + +socket_t +net_listen(Uint32 addr, Uint16 port, int backlog); + +socket_t +net_accept(socket_t server_socket); // the _all versions wait/retry until len bytes have been written/read -ssize_t net_recv(socket_t socket, void *buf, size_t len); -ssize_t net_recv_all(socket_t socket, void *buf, size_t len); -ssize_t net_send(socket_t socket, const void *buf, size_t len); -ssize_t net_send_all(socket_t socket, const void *buf, size_t len); +ssize_t +net_recv(socket_t socket, void *buf, size_t len); + +ssize_t +net_recv_all(socket_t socket, void *buf, size_t len); + +ssize_t +net_send(socket_t socket, const void *buf, size_t len); + +ssize_t +net_send_all(socket_t socket, const void *buf, size_t len); + // how is SHUT_RD (read), SHUT_WR (write) or SHUT_RDWR (both) -SDL_bool net_shutdown(socket_t socket, int how); -SDL_bool net_close(socket_t socket); +SDL_bool +net_shutdown(socket_t socket, int how); + +SDL_bool +net_close(socket_t socket); #endif diff --git a/app/src/recorder.c b/app/src/recorder.c index 2d47487f..db9d8a7a 100644 --- a/app/src/recorder.c +++ b/app/src/recorder.c @@ -9,7 +9,8 @@ static const AVRational SCRCPY_TIME_BASE = {1, 1000000}; // timestamps in us -static const AVOutputFormat *find_muxer(const char *name) { +static const AVOutputFormat * +find_muxer(const char *name) { #ifdef SCRCPY_LAVF_HAS_NEW_MUXER_ITERATOR_API void *opaque = NULL; #endif @@ -25,10 +26,11 @@ static const AVOutputFormat *find_muxer(const char *name) { return oformat; } -SDL_bool recorder_init(struct recorder *recorder, - const char *filename, - enum recorder_format format, - struct size declared_frame_size) { +SDL_bool +recorder_init(struct recorder *recorder, + const char *filename, + enum recorder_format format, + struct size declared_frame_size) { recorder->filename = SDL_strdup(filename); if (!recorder->filename) { LOGE("Cannot strdup filename"); @@ -42,7 +44,8 @@ SDL_bool recorder_init(struct recorder *recorder, return SDL_TRUE; } -void recorder_destroy(struct recorder *recorder) { +void +recorder_destroy(struct recorder *recorder) { SDL_free(recorder->filename); } @@ -55,7 +58,8 @@ recorder_get_format_name(enum recorder_format format) { } } -SDL_bool recorder_open(struct recorder *recorder, AVCodec *input_codec) { +SDL_bool +recorder_open(struct recorder *recorder, AVCodec *input_codec) { const char *format_name = recorder_get_format_name(recorder->format); SDL_assert(format_name); const AVOutputFormat *format = find_muxer(format_name); @@ -110,7 +114,8 @@ SDL_bool recorder_open(struct recorder *recorder, AVCodec *input_codec) { return SDL_TRUE; } -void recorder_close(struct recorder *recorder) { +void +recorder_close(struct recorder *recorder) { int ret = av_write_trailer(recorder->ctx); if (ret < 0) { LOGE("Failed to write trailer to %s", recorder->filename); @@ -161,7 +166,8 @@ recorder_rescale_packet(struct recorder *recorder, AVPacket *packet) { av_packet_rescale_ts(packet, SCRCPY_TIME_BASE, ostream->time_base); } -SDL_bool recorder_write(struct recorder *recorder, AVPacket *packet) { +SDL_bool +recorder_write(struct recorder *recorder, AVPacket *packet) { if (!recorder->header_written) { SDL_bool ok = recorder_write_header(recorder, packet); if (!ok) { diff --git a/app/src/recorder.h b/app/src/recorder.h index 203c51b4..5ead6f3f 100644 --- a/app/src/recorder.h +++ b/app/src/recorder.h @@ -19,16 +19,20 @@ struct recorder { SDL_bool header_written; }; -SDL_bool recorder_init(struct recorder *recoder, - const char *filename, - enum recorder_format format, - struct size declared_frame_size); +SDL_bool +recorder_init(struct recorder *recoder, const char *filename, + enum recorder_format format, struct size declared_frame_size); -void recorder_destroy(struct recorder *recorder); +void +recorder_destroy(struct recorder *recorder); -SDL_bool recorder_open(struct recorder *recorder, AVCodec *input_codec); -void recorder_close(struct recorder *recorder); +SDL_bool +recorder_open(struct recorder *recorder, AVCodec *input_codec); -SDL_bool recorder_write(struct recorder *recorder, AVPacket *packet); +void +recorder_close(struct recorder *recorder); + +SDL_bool +recorder_write(struct recorder *recorder, AVPacket *packet); #endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 387ce4e0..fde82465 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -51,8 +51,10 @@ static struct input_manager input_manager = { // // // -static int event_watcher(void *data, SDL_Event *event) { - if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED) { +static int +event_watcher(void *data, SDL_Event *event) { + if (event->type == SDL_WINDOWEVENT + && event->window.event == SDL_WINDOWEVENT_RESIZED) { // called from another thread, not very safe, but it's a workaround! screen_render(&screen); } @@ -60,12 +62,14 @@ static int event_watcher(void *data, SDL_Event *event) { } #endif -static SDL_bool is_apk(const char *file) { +static SDL_bool +is_apk(const char *file) { const char *ext = strrchr(file, '.'); return ext && !strcmp(ext, ".apk"); } -static SDL_bool event_loop(void) { +static SDL_bool +event_loop(void) { #ifdef CONTINUOUS_RESIZING_WORKAROUND SDL_AddEventWatch(event_watcher, NULL); #endif @@ -104,14 +108,17 @@ static SDL_bool event_loop(void) { input_manager_process_key(&input_manager, &event.key); break; case SDL_MOUSEMOTION: - input_manager_process_mouse_motion(&input_manager, &event.motion); + input_manager_process_mouse_motion(&input_manager, + &event.motion); break; case SDL_MOUSEWHEEL: - input_manager_process_mouse_wheel(&input_manager, &event.wheel); + input_manager_process_mouse_wheel(&input_manager, + &event.wheel); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: - input_manager_process_mouse_button(&input_manager, &event.button); + input_manager_process_mouse_button(&input_manager, + &event.button); break; case SDL_DROPFILE: { file_handler_action_t action; @@ -128,7 +135,8 @@ static SDL_bool event_loop(void) { return SDL_FALSE; } -static process_t set_show_touches_enabled(const char *serial, SDL_bool enabled) { +static process_t +set_show_touches_enabled(const char *serial, SDL_bool enabled) { const char *value = enabled ? "1" : "0"; const char *const adb_cmd[] = { "shell", "settings", "put", "system", "show_touches", value @@ -136,12 +144,14 @@ static process_t set_show_touches_enabled(const char *serial, SDL_bool enabled) return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd)); } -static void wait_show_touches(process_t process) { +static void +wait_show_touches(process_t process) { // reap the process, ignore the result process_check_success(process, "show_touches"); } -static SDL_LogPriority sdl_priority_from_av_level(int level) { +static SDL_LogPriority +sdl_priority_from_av_level(int level) { switch (level) { case AV_LOG_PANIC: case AV_LOG_FATAL: @@ -175,7 +185,8 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) { SDL_free(local_fmt); } -SDL_bool scrcpy(const struct scrcpy_options *options) { +SDL_bool +scrcpy(const struct scrcpy_options *options) { SDL_bool record = !!options->record_filename; if (!server_start(&server, options->serial, options->port, options->max_size, options->bit_rate, options->crop, @@ -208,9 +219,9 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { char device_name[DEVICE_NAME_FIELD_LENGTH]; struct size frame_size; - // screenrecord does not send frames when the screen content does not change - // therefore, we transmit the screen size before the video stream, to be able - // to init the window immediately + // screenrecord does not send frames when the screen content does not + // change therefore, we transmit the screen size before the video stream, + // to be able to init the window immediately if (!device_read_info(device_socket, device_name, &frame_size)) { server_stop(&server); ret = SDL_FALSE; @@ -273,7 +284,8 @@ SDL_bool scrcpy(const struct scrcpy_options *options) { goto finally_destroy_controller; } - if (!screen_init_rendering(&screen, device_name, frame_size, options->always_on_top)) { + if (!screen_init_rendering(&screen, device_name, frame_size, + options->always_on_top)) { ret = SDL_FALSE; goto finally_stop_and_join_controller; } @@ -328,7 +340,8 @@ finally_destroy_server: wait_show_touches(proc_show_touches); } LOGI("Disable show_touches"); - proc_show_touches = set_show_touches_enabled(options->serial, SDL_FALSE); + proc_show_touches = set_show_touches_enabled(options->serial, + SDL_FALSE); wait_show_touches(proc_show_touches); } diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index ff7f482a..ee3160cd 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -18,6 +18,7 @@ struct scrcpy_options { SDL_bool no_window; }; -SDL_bool scrcpy(const struct scrcpy_options *options); +SDL_bool +scrcpy(const struct scrcpy_options *options); #endif diff --git a/app/src/screen.c b/app/src/screen.c index 54920c94..5da96b93 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -12,7 +12,8 @@ #define DISPLAY_MARGINS 96 -SDL_bool sdl_init_and_configure(void) { +SDL_bool +sdl_init_and_configure(void) { if (SDL_Init(SDL_INIT_VIDEO)) { LOGC("Could not initialize SDL: %s", SDL_GetError()); return SDL_FALSE; @@ -39,7 +40,8 @@ SDL_bool sdl_init_and_configure(void) { } // get the window size in a struct size -static struct size get_native_window_size(SDL_Window *window) { +static struct size +get_native_window_size(SDL_Window *window) { int width; int height; SDL_GetWindowSize(window, &width, &height); @@ -51,7 +53,8 @@ static struct size get_native_window_size(SDL_Window *window) { } // get the windowed window size -static struct size get_window_size(const struct screen *screen) { +static struct size +get_window_size(const struct screen *screen) { if (screen->fullscreen) { return screen->windowed_window_size; } @@ -59,7 +62,8 @@ static struct size get_window_size(const struct screen *screen) { } // set the window size to be applied when fullscreen is disabled -static void set_window_size(struct screen *screen, struct size new_size) { +static void +set_window_size(struct screen *screen, struct size new_size) { // setting the window size during fullscreen is implementation defined, // so apply the resize only after fullscreen is disabled if (screen->fullscreen) { @@ -71,7 +75,8 @@ static void set_window_size(struct screen *screen, struct size new_size) { } // get the preferred display bounds (i.e. the screen bounds with some margins) -static SDL_bool get_preferred_display_bounds(struct size *bounds) { +static SDL_bool +get_preferred_display_bounds(struct size *bounds) { SDL_Rect rect; #ifdef SCRCPY_SDL_HAS_GET_DISPLAY_USABLE_BOUNDS # define GET_DISPLAY_BOUNDS(i, r) SDL_GetDisplayUsableBounds((i), (r)) @@ -89,10 +94,12 @@ static SDL_bool get_preferred_display_bounds(struct size *bounds) { } // return the optimal size of the window, with the following constraints: -// - it attempts to keep at least one dimension of the current_size (i.e. it crops the black borders) +// - it attempts to keep at least one dimension of the current_size (i.e. it +// crops the black borders) // - it keeps the aspect ratio // - it scales down to make it fit in the display_size -static struct size get_optimal_size(struct size current_size, struct size frame_size) { +static struct size +get_optimal_size(struct size current_size, struct size frame_size) { if (frame_size.width == 0 || frame_size.height == 0) { // avoid division by 0 return current_size; @@ -117,7 +124,8 @@ static struct size get_optimal_size(struct size current_size, struct size frame_ // remove black borders on top and bottom h = frame_size.height * w / frame_size.width; } else { - // remove black borders on left and right (or none at all if it already fits) + // remove black borders on left and right (or none at all if it already + // fits) w = frame_size.width * h / frame_size.height; } @@ -127,29 +135,33 @@ static struct size get_optimal_size(struct size current_size, struct size frame_ } // same as get_optimal_size(), but read the current size from the window -static inline struct size get_optimal_window_size(const struct screen *screen, struct size frame_size) { +static inline struct size +get_optimal_window_size(const struct screen *screen, struct size frame_size) { struct size current_size = get_window_size(screen); return get_optimal_size(current_size, frame_size); } // initially, there is no current size, so use the frame size as current size -static inline struct size get_initial_optimal_size(struct size frame_size) { +static inline struct size +get_initial_optimal_size(struct size frame_size) { return get_optimal_size(frame_size, frame_size); } -void screen_init(struct screen *screen) { +void +screen_init(struct screen *screen) { *screen = (struct screen) SCREEN_INITIALIZER; } -static inline SDL_Texture *create_texture(SDL_Renderer *renderer, struct size frame_size) { - return SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, +static inline SDL_Texture * +create_texture(SDL_Renderer *renderer, struct size frame_size) { + return SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, + SDL_TEXTUREACCESS_STREAMING, frame_size.width, frame_size.height); } -SDL_bool screen_init_rendering(struct screen *screen, - const char *device_name, - struct size frame_size, - SDL_bool always_on_top) { +SDL_bool +screen_init_rendering(struct screen *screen, const char *device_name, + struct size frame_size, SDL_bool always_on_top) { screen->frame_size = frame_size; struct size window_size = get_initial_optimal_size(frame_size); @@ -166,21 +178,25 @@ SDL_bool screen_init_rendering(struct screen *screen, #endif } - screen->window = SDL_CreateWindow(device_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - window_size.width, window_size.height, window_flags); + screen->window = SDL_CreateWindow(device_name, SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + window_size.width, window_size.height, + window_flags); if (!screen->window) { LOGC("Could not create window: %s", SDL_GetError()); return SDL_FALSE; } - screen->renderer = SDL_CreateRenderer(screen->window, -1, SDL_RENDERER_ACCELERATED); + screen->renderer = SDL_CreateRenderer(screen->window, -1, + SDL_RENDERER_ACCELERATED); if (!screen->renderer) { LOGC("Could not create renderer: %s", SDL_GetError()); screen_destroy(screen); return SDL_FALSE; } - if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width, frame_size.height)) { + if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width, + frame_size.height)) { LOGE("Could not set renderer logical size: %s", SDL_GetError()); screen_destroy(screen); return SDL_FALSE; @@ -195,7 +211,8 @@ SDL_bool screen_init_rendering(struct screen *screen, SDL_SetWindowIcon(screen->window, icon); SDL_FreeSurface(icon); - LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width, frame_size.height); + LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width, + frame_size.height); screen->texture = create_texture(screen->renderer, frame_size); if (!screen->texture) { LOGC("Could not create texture: %s", SDL_GetError()); @@ -206,11 +223,13 @@ SDL_bool screen_init_rendering(struct screen *screen, return SDL_TRUE; } -void screen_show_window(struct screen *screen) { +void +screen_show_window(struct screen *screen) { SDL_ShowWindow(screen->window); } -void screen_destroy(struct screen *screen) { +void +screen_destroy(struct screen *screen) { if (screen->texture) { SDL_DestroyTexture(screen->texture); } @@ -223,9 +242,12 @@ void screen_destroy(struct screen *screen) { } // recreate the texture and resize the window if the frame size has changed -static SDL_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) { - if (SDL_RenderSetLogicalSize(screen->renderer, new_frame_size.width, new_frame_size.height)) { +static SDL_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) { + if (SDL_RenderSetLogicalSize(screen->renderer, new_frame_size.width, + new_frame_size.height)) { LOGE("Could not set renderer logical size: %s", SDL_GetError()); return SDL_FALSE; } @@ -235,8 +257,10 @@ static SDL_bool prepare_for_frame(struct screen *screen, struct size new_frame_s struct size current_size = get_window_size(screen); struct size target_size = { - (Uint32) current_size.width * new_frame_size.width / screen->frame_size.width, - (Uint32) current_size.height * new_frame_size.height / screen->frame_size.height, + (Uint32) current_size.width * new_frame_size.width + / screen->frame_size.width, + (Uint32) current_size.height * new_frame_size.height + / screen->frame_size.height, }; target_size = get_optimal_size(target_size, new_frame_size); set_window_size(screen, target_size); @@ -256,14 +280,16 @@ static SDL_bool prepare_for_frame(struct screen *screen, struct size new_frame_s } // write the frame into the texture -static void update_texture(struct screen *screen, const AVFrame *frame) { +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]); } -SDL_bool screen_update_frame(struct screen *screen, struct video_buffer *vb) { +SDL_bool +screen_update_frame(struct screen *screen, struct video_buffer *vb) { mutex_lock(vb->mutex); const AVFrame *frame = video_buffer_consume_rendered_frame(vb); struct size new_frame_size = {frame->width, frame->height}; @@ -278,13 +304,15 @@ SDL_bool screen_update_frame(struct screen *screen, struct video_buffer *vb) { return SDL_TRUE; } -void screen_render(struct screen *screen) { +void +screen_render(struct screen *screen) { SDL_RenderClear(screen->renderer); SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL); SDL_RenderPresent(screen->renderer); } -void screen_switch_fullscreen(struct screen *screen) { +void +screen_switch_fullscreen(struct screen *screen) { if (!screen->fullscreen) { // going to fullscreen, store the current windowed window size screen->windowed_window_size = get_native_window_size(screen->window); @@ -298,24 +326,30 @@ void screen_switch_fullscreen(struct screen *screen) { screen->fullscreen = !screen->fullscreen; if (!screen->fullscreen) { // fullscreen disabled, restore expected windowed window size - SDL_SetWindowSize(screen->window, screen->windowed_window_size.width, screen->windowed_window_size.height); + SDL_SetWindowSize(screen->window, screen->windowed_window_size.width, + screen->windowed_window_size.height); } LOGD("Switched to %s mode", screen->fullscreen ? "fullscreen" : "windowed"); screen_render(screen); } -void screen_resize_to_fit(struct screen *screen) { +void +screen_resize_to_fit(struct screen *screen) { if (!screen->fullscreen) { - struct size optimal_size = get_optimal_window_size(screen, screen->frame_size); - SDL_SetWindowSize(screen->window, optimal_size.width, optimal_size.height); + struct size optimal_size = get_optimal_window_size(screen, + screen->frame_size); + SDL_SetWindowSize(screen->window, optimal_size.width, + optimal_size.height); LOGD("Resized to optimal size"); } } -void screen_resize_to_pixel_perfect(struct screen *screen) { +void +screen_resize_to_pixel_perfect(struct screen *screen) { if (!screen->fullscreen) { - SDL_SetWindowSize(screen->window, screen->frame_size.width, screen->frame_size.height); + SDL_SetWindowSize(screen->window, screen->frame_size.width, + screen->frame_size.height); LOGD("Resized to pixel-perfect"); } } diff --git a/app/src/screen.h b/app/src/screen.h index f857e981..51f9396d 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -38,36 +38,44 @@ struct screen { } // init SDL and set appropriate hints -SDL_bool sdl_init_and_configure(void); +SDL_bool +sdl_init_and_configure(void); // initialize default values -void screen_init(struct screen *screen); +void +screen_init(struct screen *screen); // initialize screen, create window, renderer and texture (window is hidden) -SDL_bool screen_init_rendering(struct screen *screen, - const char *device_name, - struct size frame_size, - SDL_bool always_on_top); +SDL_bool +screen_init_rendering(struct screen *screen, const char *device_name, + struct size frame_size, SDL_bool always_on_top); // show the window -void screen_show_window(struct screen *screen); +void +screen_show_window(struct screen *screen); // destroy window, renderer and texture (if any) -void screen_destroy(struct screen *screen); +void +screen_destroy(struct screen *screen); // resize if necessary and write the rendered frame into the texture -SDL_bool screen_update_frame(struct screen *screen, struct video_buffer *vb); +SDL_bool +screen_update_frame(struct screen *screen, struct video_buffer *vb); // render the texture to the renderer -void screen_render(struct screen *screen); +void +screen_render(struct screen *screen); // switch the fullscreen mode -void screen_switch_fullscreen(struct screen *screen); +void +screen_switch_fullscreen(struct screen *screen); // resize window to optimal size (remove black borders) -void screen_resize_to_fit(struct screen *screen); +void +screen_resize_to_fit(struct screen *screen); // resize window to 1:1 (pixel-perfect) -void screen_resize_to_pixel_perfect(struct screen *screen); +void +screen_resize_to_pixel_perfect(struct screen *screen); #endif diff --git a/app/src/server.c b/app/src/server.c index 7835e716..1dce347f 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -21,7 +21,8 @@ #define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar" -static const char *get_server_path(void) { +static const char * +get_server_path(void) { const char *server_path = getenv("SCRCPY_SERVER_PATH"); if (!server_path) { server_path = DEFAULT_SERVER_PATH; @@ -29,32 +30,38 @@ static const char *get_server_path(void) { return server_path; } -static SDL_bool push_server(const char *serial) { +static SDL_bool +push_server(const char *serial) { process_t process = adb_push(serial, get_server_path(), DEVICE_SERVER_PATH); return process_check_success(process, "adb push"); } -static SDL_bool enable_tunnel_reverse(const char *serial, Uint16 local_port) { +static SDL_bool +enable_tunnel_reverse(const char *serial, Uint16 local_port) { process_t process = adb_reverse(serial, SOCKET_NAME, local_port); return process_check_success(process, "adb reverse"); } -static SDL_bool disable_tunnel_reverse(const char *serial) { +static SDL_bool +disable_tunnel_reverse(const char *serial) { process_t process = adb_reverse_remove(serial, SOCKET_NAME); return process_check_success(process, "adb reverse --remove"); } -static SDL_bool enable_tunnel_forward(const char *serial, Uint16 local_port) { +static SDL_bool +enable_tunnel_forward(const char *serial, Uint16 local_port) { process_t process = adb_forward(serial, local_port, SOCKET_NAME); return process_check_success(process, "adb forward"); } -static SDL_bool disable_tunnel_forward(const char *serial, Uint16 local_port) { +static SDL_bool +disable_tunnel_forward(const char *serial, Uint16 local_port) { process_t process = adb_forward_remove(serial, local_port); return process_check_success(process, "adb forward --remove"); } -static SDL_bool enable_tunnel(struct server *server) { +static SDL_bool +enable_tunnel(struct server *server) { if (enable_tunnel_reverse(server->serial, server->local_port)) { return SDL_TRUE; } @@ -64,17 +71,19 @@ static SDL_bool enable_tunnel(struct server *server) { return enable_tunnel_forward(server->serial, server->local_port); } -static SDL_bool disable_tunnel(struct server *server) { +static SDL_bool +disable_tunnel(struct server *server) { if (server->tunnel_forward) { return disable_tunnel_forward(server->serial, server->local_port); } return disable_tunnel_reverse(server->serial); } -static process_t execute_server(const char *serial, - Uint16 max_size, Uint32 bit_rate, - SDL_bool tunnel_forward, const char *crop, - SDL_bool send_frame_meta) { +static process_t +execute_server(const char *serial, + Uint16 max_size, Uint32 bit_rate, + SDL_bool tunnel_forward, const char *crop, + SDL_bool send_frame_meta) { char max_size_string[6]; char bit_rate_string[11]; sprintf(max_size_string, "%"PRIu16, max_size); @@ -96,11 +105,13 @@ static process_t execute_server(const char *serial, #define IPV4_LOCALHOST 0x7F000001 -static socket_t listen_on_port(Uint16 port) { +static socket_t +listen_on_port(Uint16 port) { return net_listen(IPV4_LOCALHOST, port, 1); } -static socket_t connect_and_read_byte(Uint16 port) { +static socket_t +connect_and_read_byte(Uint16 port) { socket_t socket = net_connect(IPV4_LOCALHOST, port); if (socket == INVALID_SOCKET) { return INVALID_SOCKET; @@ -116,7 +127,8 @@ static socket_t connect_and_read_byte(Uint16 port) { return socket; } -static socket_t connect_to_server(Uint16 port, Uint32 attempts, Uint32 delay) { +static socket_t +connect_to_server(Uint16 port, Uint32 attempts, Uint32 delay) { do { LOGD("Remaining connection attempts: %d", (int) attempts); socket_t socket = connect_and_read_byte(port); @@ -131,7 +143,8 @@ static socket_t connect_to_server(Uint16 port, Uint32 attempts, Uint32 delay) { return INVALID_SOCKET; } -static void close_socket(socket_t *socket) { +static void +close_socket(socket_t *socket) { SDL_assert(*socket != INVALID_SOCKET); net_shutdown(*socket, SHUT_RDWR); if (!net_close(*socket)) { @@ -141,13 +154,15 @@ static void close_socket(socket_t *socket) { *socket = INVALID_SOCKET; } -void server_init(struct server *server) { +void +server_init(struct server *server) { *server = (struct server) SERVER_INITIALIZER; } -SDL_bool server_start(struct server *server, const char *serial, - Uint16 local_port, Uint16 max_size, Uint32 bit_rate, - const char *crop, SDL_bool send_frame_meta) { +SDL_bool +server_start(struct server *server, const char *serial, + Uint16 local_port, Uint16 max_size, Uint32 bit_rate, + const char *crop, SDL_bool send_frame_meta) { server->local_port = local_port; if (serial) { @@ -173,8 +188,9 @@ SDL_bool server_start(struct server *server, const char *serial, // At the application level, the device part is "the server" because it // serves video stream and control. However, at the network level, the // client listens and the server connects to the client. That way, the - // client can listen before starting the server app, so there is no need to - // try to connect until the server socket is listening on the device. + // client can listen before starting the server app, so there is no + // need to try to connect until the server socket is listening on the + // device. server->server_socket = listen_on_port(local_port); if (server->server_socket == INVALID_SOCKET) { @@ -204,13 +220,15 @@ SDL_bool server_start(struct server *server, const char *serial, return SDL_TRUE; } -socket_t server_connect_to(struct server *server) { +socket_t +server_connect_to(struct server *server) { if (!server->tunnel_forward) { server->device_socket = net_accept(server->server_socket); } else { Uint32 attempts = 100; Uint32 delay = 100; // ms - server->device_socket = connect_to_server(server->local_port, attempts, delay); + server->device_socket = connect_to_server(server->local_port, attempts, + delay); } if (server->device_socket == INVALID_SOCKET) { @@ -229,7 +247,8 @@ socket_t server_connect_to(struct server *server) { return server->device_socket; } -void server_stop(struct server *server) { +void +server_stop(struct server *server) { SDL_assert(server->process != PROCESS_NONE); if (!cmd_terminate(server->process)) { @@ -245,7 +264,8 @@ void server_stop(struct server *server) { } } -void server_destroy(struct server *server) { +void +server_destroy(struct server *server) { if (server->server_socket != INVALID_SOCKET) { close_socket(&server->server_socket); } diff --git a/app/src/server.h b/app/src/server.h index b9835e13..d6d2c3eb 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -27,20 +27,25 @@ struct server { } // init default values -void server_init(struct server *server); +void +server_init(struct server *server); // push, enable tunnel et start the server -SDL_bool server_start(struct server *server, const char *serial, +SDL_bool +server_start(struct server *server, const char *serial, Uint16 local_port, Uint16 max_size, Uint32 bit_rate, const char *crop, SDL_bool send_frame_meta); // block until the communication with the server is established -socket_t server_connect_to(struct server *server); +socket_t +server_connect_to(struct server *server); // disconnect and kill the server process -void server_stop(struct server *server); +void +server_stop(struct server *server); // close and release sockets -void server_destroy(struct server *server); +void +server_destroy(struct server *server); #endif diff --git a/app/src/str_util.c b/app/src/str_util.c index 892883a6..3509331a 100644 --- a/app/src/str_util.c +++ b/app/src/str_util.c @@ -8,7 +8,8 @@ # include #endif -size_t xstrncpy(char *dest, const char *src, size_t n) { +size_t +xstrncpy(char *dest, const char *src, size_t n) { size_t i; for (i = 0; i < n - 1 && src[i] != '\0'; ++i) dest[i] = src[i]; @@ -17,7 +18,8 @@ size_t xstrncpy(char *dest, const char *src, size_t n) { return src[i] == '\0' ? i : n; } -size_t xstrjoin(char *dst, const char *const tokens[], char sep, size_t n) { +size_t +xstrjoin(char *dst, const char *const tokens[], char sep, size_t n) { const char *const *remaining = tokens; const char *token = *remaining++; size_t i = 0; @@ -40,7 +42,8 @@ truncated: return n; } -char *strquote(const char *src) { +char * +strquote(const char *src) { size_t len = strlen(src); char *quoted = malloc(len + 3); if (!quoted) { @@ -55,7 +58,8 @@ char *strquote(const char *src) { #ifdef _WIN32 -wchar_t *utf8_to_wide_char(const char *utf8) { +wchar_t * +utf8_to_wide_char(const char *utf8) { int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); if (!len) { return NULL; diff --git a/app/src/str_util.h b/app/src/str_util.h index 6f4004f1..9ef06cbf 100644 --- a/app/src/str_util.h +++ b/app/src/str_util.h @@ -9,21 +9,25 @@ // - it does not write useless bytes if strlen(src) < n // - it returns the number of chars actually written (max n-1) if src has // been copied completely, or n if src has been truncated -size_t xstrncpy(char *dest, const char *src, size_t n); +size_t +xstrncpy(char *dest, const char *src, size_t n); // join tokens by sep into dst // returns the number of chars actually written (max n-1) if no trucation // occurred, or n if truncated -size_t xstrjoin(char *dst, const char *const tokens[], char sep, size_t n); +size_t +xstrjoin(char *dst, const char *const tokens[], char sep, size_t n); // quote a string // returns the new allocated string, to be freed by the caller -char *strquote(const char *src); +char * +strquote(const char *src); #ifdef _WIN32 // convert a UTF-8 string to a wchar_t string // returns the new allocated string, to be freed by the caller -wchar_t *utf8_to_wide_char(const char *utf8); +wchar_t * +utf8_to_wide_char(const char *utf8); #endif #endif diff --git a/app/src/stream.c b/app/src/stream.c index c75afa0f..2c9ba078 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -22,7 +22,8 @@ #define HEADER_SIZE 12 #define NO_PTS UINT64_C(-1) -static struct frame_meta *frame_meta_new(Uint64 pts) { +static struct frame_meta * +frame_meta_new(Uint64 pts) { struct frame_meta *meta = malloc(sizeof(*meta)); if (!meta) { return meta; @@ -32,12 +33,13 @@ static struct frame_meta *frame_meta_new(Uint64 pts) { return meta; } -static void frame_meta_delete(struct frame_meta *frame_meta) { +static void +frame_meta_delete(struct frame_meta *frame_meta) { free(frame_meta); } -static SDL_bool receiver_state_push_meta(struct receiver_state *state, - Uint64 pts) { +static SDL_bool +receiver_state_push_meta(struct receiver_state *state, Uint64 pts) { struct frame_meta *frame_meta = frame_meta_new(pts); if (!frame_meta) { return SDL_FALSE; @@ -53,7 +55,8 @@ static SDL_bool receiver_state_push_meta(struct receiver_state *state, return SDL_TRUE; } -static Uint64 receiver_state_take_meta(struct receiver_state *state) { +static Uint64 +receiver_state_take_meta(struct receiver_state *state) { struct frame_meta *frame_meta = state->frame_meta_queue; // first item SDL_assert(frame_meta); // must not be empty Uint64 pts = frame_meta->pts; @@ -62,7 +65,8 @@ static Uint64 receiver_state_take_meta(struct receiver_state *state) { return pts; } -static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { +static int +read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { struct stream *stream = opaque; struct receiver_state *state = &stream->receiver_state; @@ -121,7 +125,8 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { return r; } -static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) { +static int +read_raw_packet(void *opaque, uint8_t *buf, int buf_size) { struct stream *stream = opaque; ssize_t r = net_recv(stream->socket, buf, buf_size); if (r == -1) { @@ -133,13 +138,15 @@ static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) { return r; } -static void notify_stopped(void) { +static void +notify_stopped(void) { SDL_Event stop_event; stop_event.type = EVENT_STREAM_STOPPED; SDL_PushEvent(&stop_event); } -static int run_stream(void *data) { +static int +run_stream(void *data) { struct stream *stream = data; AVFormatContext *format_ctx = avformat_alloc_context(); @@ -246,14 +253,16 @@ end: return 0; } -void stream_init(struct stream *stream, socket_t socket, - struct decoder *decoder, struct recorder *recorder) { +void +stream_init(struct stream *stream, socket_t socket, + struct decoder *decoder, struct recorder *recorder) { stream->socket = socket; stream->decoder = decoder, stream->recorder = recorder; } -SDL_bool stream_start(struct stream *stream) { +SDL_bool +stream_start(struct stream *stream) { LOGD("Starting stream thread"); stream->thread = SDL_CreateThread(run_stream, "stream", stream); @@ -264,12 +273,14 @@ SDL_bool stream_start(struct stream *stream) { return SDL_TRUE; } -void stream_stop(struct stream *stream) { +void +stream_stop(struct stream *stream) { if (stream->decoder) { decoder_interrupt(stream->decoder); } } -void stream_join(struct stream *stream) { +void +stream_join(struct stream *stream) { SDL_WaitThread(stream->thread, NULL); } diff --git a/app/src/stream.h b/app/src/stream.h index ef78b321..d8b61857 100644 --- a/app/src/stream.h +++ b/app/src/stream.h @@ -26,10 +26,17 @@ struct stream { } receiver_state; }; -void stream_init(struct stream *stream, socket_t socket, - struct decoder *decoder, struct recorder *recorder); -SDL_bool stream_start(struct stream *stream); -void stream_stop(struct stream *stream); -void stream_join(struct stream *stream); +void +stream_init(struct stream *stream, socket_t socket, + struct decoder *decoder, struct recorder *recorder); + +SDL_bool +stream_start(struct stream *stream); + +void +stream_stop(struct stream *stream); + +void +stream_join(struct stream *stream); #endif diff --git a/app/src/sys/unix/command.c b/app/src/sys/unix/command.c index 9eb537b9..cec215aa 100644 --- a/app/src/sys/unix/command.c +++ b/app/src/sys/unix/command.c @@ -11,7 +11,8 @@ #include #include "log.h" -enum process_result cmd_execute(const char *path, const char *const argv[], pid_t *pid) { +enum process_result +cmd_execute(const char *path, const char *const argv[], pid_t *pid) { int fd[2]; if (pipe(fd) == -1) { @@ -72,15 +73,18 @@ end: return ret; } -SDL_bool cmd_terminate(pid_t pid) { +SDL_bool +cmd_terminate(pid_t pid) { if (pid <= 0) { - LOGC("Requested to kill %d, this is an error. Please report the bug.\n", (int) pid); + LOGC("Requested to kill %d, this is an error. Please report the bug.\n", + (int) pid); abort(); } return kill(pid, SIGTERM) != -1; } -SDL_bool cmd_simple_wait(pid_t pid, int *exit_code) { +SDL_bool +cmd_simple_wait(pid_t pid, int *exit_code) { int status; int code; if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status)) { diff --git a/app/src/sys/unix/net.c b/app/src/sys/unix/net.c index f2c82505..7fed5ebb 100644 --- a/app/src/sys/unix/net.c +++ b/app/src/sys/unix/net.c @@ -2,15 +2,18 @@ # include -SDL_bool net_init(void) { +SDL_bool +net_init(void) { // do nothing return SDL_TRUE; } -void net_cleanup(void) { +void +net_cleanup(void) { // do nothing } -SDL_bool net_close(socket_t socket) { +SDL_bool +net_close(socket_t socket) { return !close(socket); } diff --git a/app/src/sys/win/command.c b/app/src/sys/win/command.c index 5e9876cd..c5580946 100644 --- a/app/src/sys/win/command.c +++ b/app/src/sys/win/command.c @@ -4,7 +4,8 @@ #include "log.h" #include "str_util.h" -static int build_cmd(char *cmd, size_t len, const char *const argv[]) { +static int +build_cmd(char *cmd, size_t len, const char *const argv[]) { // Windows command-line parsing is WTF: // // only make it work for this very specific program @@ -17,7 +18,8 @@ static int build_cmd(char *cmd, size_t len, const char *const argv[]) { return 0; } -enum process_result cmd_execute(const char *path, const char *const argv[], HANDLE *handle) { +enum process_result +cmd_execute(const char *path, const char *const argv[], HANDLE *handle) { STARTUPINFOW si; PROCESS_INFORMATION pi; memset(&si, 0, sizeof(si)); @@ -40,7 +42,8 @@ enum process_result cmd_execute(const char *path, const char *const argv[], HAND #else int flags = 0; #endif - if (!CreateProcessW(NULL, wide, NULL, NULL, FALSE, flags, NULL, NULL, &si, &pi)) { + if (!CreateProcessW(NULL, wide, NULL, NULL, FALSE, flags, NULL, NULL, &si, + &pi)) { free(wide); *handle = NULL; if (GetLastError() == ERROR_FILE_NOT_FOUND) { @@ -54,13 +57,16 @@ enum process_result cmd_execute(const char *path, const char *const argv[], HAND return PROCESS_SUCCESS; } -SDL_bool cmd_terminate(HANDLE handle) { +SDL_bool +cmd_terminate(HANDLE handle) { return TerminateProcess(handle, 1) && CloseHandle(handle); } -SDL_bool cmd_simple_wait(HANDLE handle, DWORD *exit_code) { +SDL_bool +cmd_simple_wait(HANDLE handle, DWORD *exit_code) { DWORD code; - if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 || !GetExitCodeProcess(handle, &code)) { + if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 + || !GetExitCodeProcess(handle, &code)) { // cannot wait or retrieve the exit code code = -1; // max value, it's unsigned } diff --git a/app/src/sys/win/net.c b/app/src/sys/win/net.c index 140c1bce..0ca55f9b 100644 --- a/app/src/sys/win/net.c +++ b/app/src/sys/win/net.c @@ -2,7 +2,8 @@ #include "log.h" -SDL_bool net_init(void) { +SDL_bool +net_init(void) { WSADATA wsa; int res = WSAStartup(MAKEWORD(2, 2), &wsa) < 0; if (res < 0) { @@ -12,10 +13,12 @@ SDL_bool net_init(void) { return SDL_TRUE; } -void net_cleanup(void) { +void +net_cleanup(void) { WSACleanup(); } -SDL_bool net_close(socket_t socket) { +SDL_bool +net_close(socket_t socket) { return !closesocket(socket); } diff --git a/app/src/tiny_xpm.c b/app/src/tiny_xpm.c index 3b80b88e..b9efd575 100644 --- a/app/src/tiny_xpm.c +++ b/app/src/tiny_xpm.c @@ -10,7 +10,8 @@ struct index { Uint32 color; }; -static SDL_bool find_color(struct index *index, int len, char c, Uint32 *color) { +static SDL_bool +find_color(struct index *index, int len, char c, Uint32 *color) { // there are typically very few color, so it's ok to iterate over the array for (int i = 0; i < len; ++i) { if (index[i].c == c) { @@ -30,7 +31,8 @@ static SDL_bool find_color(struct index *index, int len, char c, Uint32 *color) // // Parameter is not "const char *" because XPM formats are generally stored in a // (non-const) "char *" -SDL_Surface *read_xpm(char *xpm[]) { +SDL_Surface * +read_xpm(char *xpm[]) { #if SDL_ASSERT_LEVEL >= 2 // patch the XPM to change the icon color in debug mode xpm[2] = ". c #CC00CC"; diff --git a/app/src/tiny_xpm.h b/app/src/tiny_xpm.h index 4bee7052..85dea5c2 100644 --- a/app/src/tiny_xpm.h +++ b/app/src/tiny_xpm.h @@ -3,6 +3,7 @@ #include -SDL_Surface *read_xpm(char *xpm[]); +SDL_Surface * +read_xpm(char *xpm[]); #endif diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index 248b450a..f7c34bef 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -9,7 +9,8 @@ #include "lock_util.h" #include "log.h" -SDL_bool video_buffer_init(struct video_buffer *vb) { +SDL_bool +video_buffer_init(struct video_buffer *vb) { if (!(vb->decoding_frame = av_frame_alloc())) { goto error_0; } @@ -45,7 +46,8 @@ error_0: return SDL_FALSE; } -void video_buffer_destroy(struct video_buffer *vb) { +void +video_buffer_destroy(struct video_buffer *vb) { #ifndef SKIP_FRAMES SDL_DestroyCond(vb->rendering_frame_consumed_cond); #endif @@ -54,13 +56,15 @@ void video_buffer_destroy(struct video_buffer *vb) { av_frame_free(&vb->decoding_frame); } -static void video_buffer_swap_frames(struct video_buffer *vb) { +static void +video_buffer_swap_frames(struct video_buffer *vb) { AVFrame *tmp = vb->decoding_frame; vb->decoding_frame = vb->rendering_frame; vb->rendering_frame = tmp; } -SDL_bool video_buffer_offer_decoded_frame(struct video_buffer *vb) { +SDL_bool +video_buffer_offer_decoded_frame(struct video_buffer *vb) { mutex_lock(vb->mutex); #ifndef SKIP_FRAMES // if SKIP_FRAMES is disabled, then the decoder must wait for the current @@ -83,7 +87,8 @@ SDL_bool video_buffer_offer_decoded_frame(struct video_buffer *vb) { return previous_frame_consumed; } -const AVFrame *video_buffer_consume_rendered_frame(struct video_buffer *vb) { +const AVFrame * +video_buffer_consume_rendered_frame(struct video_buffer *vb) { SDL_assert(!vb->rendering_frame_consumed); vb->rendering_frame_consumed = SDL_TRUE; if (vb->fps_counter.started) { @@ -97,7 +102,8 @@ const AVFrame *video_buffer_consume_rendered_frame(struct video_buffer *vb) { return vb->rendering_frame; } -void video_buffer_interrupt(struct video_buffer *vb) { +void +video_buffer_interrupt(struct video_buffer *vb) { #ifdef SKIP_FRAMES (void) vb; // unused #else diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index 4ad422f8..e9a72f50 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -22,21 +22,27 @@ struct video_buffer { struct fps_counter fps_counter; }; -SDL_bool video_buffer_init(struct video_buffer *vb); -void video_buffer_destroy(struct video_buffer *vb); +SDL_bool +video_buffer_init(struct video_buffer *vb); + +void +video_buffer_destroy(struct video_buffer *vb); // set the decoded frame as ready for rendering // this function locks frames->mutex during its execution // returns true if the previous frame had been consumed -SDL_bool video_buffer_offer_decoded_frame(struct video_buffer *vb); +SDL_bool +video_buffer_offer_decoded_frame(struct video_buffer *vb); // mark the rendering frame as consumed and return it // MUST be called with frames->mutex locked!!! // the caller is expected to render the returned frame to some texture before // unlocking frames->mutex -const AVFrame *video_buffer_consume_rendered_frame(struct video_buffer *vb); +const AVFrame * +video_buffer_consume_rendered_frame(struct video_buffer *vb); // wake up and avoid any blocking call -void video_buffer_interrupt(struct video_buffer *vb); +void +video_buffer_interrupt(struct video_buffer *vb); #endif From 33ccb1368f013d803854e8980d6148503d4cb683 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 21:49:39 +0100 Subject: [PATCH 14/24] Extract event processing out of event_loop() To avoid too many levels of nested blocks, move the event handling logic in a separate function. --- app/src/scrcpy.c | 123 +++++++++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 53 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index fde82465..19c3d0e6 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -68,6 +68,70 @@ is_apk(const char *file) { return ext && !strcmp(ext, ".apk"); } +enum event_result { + EVENT_RESULT_CONTINUE, + EVENT_RESULT_STOPPED_BY_USER, + EVENT_RESULT_STOPPED_BY_EOS, +}; + +static enum event_result +handle_event(SDL_Event *event) { + switch (event->type) { + case EVENT_STREAM_STOPPED: + LOGD("Video stream stopped"); + return EVENT_RESULT_STOPPED_BY_EOS; + 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 = SDL_TRUE; + // this is the very first frame, show the window + screen_show_window(&screen); + } + if (!screen_update_frame(&screen, &video_buffer)) { + return SDL_FALSE; + } + break; + case SDL_WINDOWEVENT: + switch (event->window.event) { + case SDL_WINDOWEVENT_EXPOSED: + case SDL_WINDOWEVENT_SIZE_CHANGED: + screen_render(&screen); + break; + } + break; + case SDL_TEXTINPUT: + input_manager_process_text_input(&input_manager, &event->text); + break; + case SDL_KEYDOWN: + case SDL_KEYUP: + input_manager_process_key(&input_manager, &event->key); + break; + case SDL_MOUSEMOTION: + input_manager_process_mouse_motion(&input_manager, &event->motion); + break; + case SDL_MOUSEWHEEL: + input_manager_process_mouse_wheel(&input_manager, &event->wheel); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + input_manager_process_mouse_button(&input_manager, &event->button); + break; + case SDL_DROPFILE: { + file_handler_action_t action; + if (is_apk(event->drop.file)) { + action = ACTION_INSTALL_APK; + } else { + action = ACTION_PUSH_FILE; + } + file_handler_request(&file_handler, action, event->drop.file); + break; + } + } + return EVENT_RESULT_CONTINUE; +} + static SDL_bool event_loop(void) { #ifdef CONTINUOUS_RESIZING_WORKAROUND @@ -75,61 +139,14 @@ event_loop(void) { #endif SDL_Event event; while (SDL_WaitEvent(&event)) { - switch (event.type) { - case EVENT_STREAM_STOPPED: - LOGD("Video stream stopped"); - return SDL_FALSE; - case SDL_QUIT: - LOGD("User requested to quit"); + enum event_result result = handle_event(&event); + switch (result) { + case EVENT_RESULT_STOPPED_BY_USER: return SDL_TRUE; - case EVENT_NEW_FRAME: - if (!screen.has_frame) { - screen.has_frame = SDL_TRUE; - // this is the very first frame, show the window - screen_show_window(&screen); - } - if (!screen_update_frame(&screen, &video_buffer)) { - return SDL_FALSE; - } + case EVENT_RESULT_STOPPED_BY_EOS: + return SDL_FALSE; + case EVENT_RESULT_CONTINUE: break; - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_EXPOSED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - screen_render(&screen); - break; - } - break; - case SDL_TEXTINPUT: - input_manager_process_text_input(&input_manager, &event.text); - break; - case SDL_KEYDOWN: - case SDL_KEYUP: - input_manager_process_key(&input_manager, &event.key); - break; - case SDL_MOUSEMOTION: - input_manager_process_mouse_motion(&input_manager, - &event.motion); - break; - case SDL_MOUSEWHEEL: - input_manager_process_mouse_wheel(&input_manager, - &event.wheel); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - input_manager_process_mouse_button(&input_manager, - &event.button); - break; - case SDL_DROPFILE: { - file_handler_action_t action; - if (is_apk(event.drop.file)) { - action = ACTION_INSTALL_APK; - } else { - action = ACTION_PUSH_FILE; - } - file_handler_request(&file_handler, action, event.drop.file); - break; - } } } return SDL_FALSE; From 36191b7eec817b8ab6d87decd379b7cab2ce5834 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 21:32:31 +0100 Subject: [PATCH 15/24] Avoid unnecessary call if display is disabled If --no-window is passed, there is no need to register an event watcher. --- app/src/scrcpy.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 19c3d0e6..03d24bc7 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -133,9 +133,11 @@ handle_event(SDL_Event *event) { } static SDL_bool -event_loop(void) { +event_loop(SDL_bool display) { #ifdef CONTINUOUS_RESIZING_WORKAROUND - SDL_AddEventWatch(event_watcher, NULL); + if (display) { + SDL_AddEventWatch(event_watcher, NULL); + } #endif SDL_Event event; while (SDL_WaitEvent(&event)) { @@ -317,7 +319,7 @@ scrcpy(const struct scrcpy_options *options) { show_touches_waited = SDL_TRUE; } - ret = event_loop(); + ret = event_loop(display); LOGD("quit..."); screen_destroy(&screen); From db6644f1f918604ce520da412de728d598cc0024 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 22:42:28 +0100 Subject: [PATCH 16/24] Add missing no_window initialization Initialize the field no_window in "struct args" --- app/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main.c b/app/src/main.c index 92b1507a..d7816c76 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -395,6 +395,7 @@ main(int argc, char *argv[]) { .max_size = DEFAULT_MAX_SIZE, .bit_rate = DEFAULT_BIT_RATE, .always_on_top = SDL_FALSE, + .no_window = SDL_FALSE, }; if (!parse_args(&args, argc, argv)) { return 1; From 163cd36ccc1257aac8201ff864b7d75ba939f70f Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 22:46:46 +0100 Subject: [PATCH 17/24] Rename -n/--no-window to -N/--no-display The description of scrcpy is "Display and control your Android device". We want an option to disable display, another one to disable control. For naming consistency, name it --no-display. Also change the shortname to -N, so that we can use -n for --no-control later. --- README.md | 4 ++-- app/src/main.c | 27 ++++++++++++++------------- app/src/scrcpy.c | 2 +- app/src/scrcpy.h | 2 +- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ed40f21a..a36c81f8 100644 --- a/README.md +++ b/README.md @@ -168,8 +168,8 @@ scrcpy -r file.mkv To disable mirroring while recording: ```bash -scrcpy --no-window --record file.mp4 -scrcpy -nr file.mkv +scrcpy --no-display --record file.mp4 +scrcpy -Nr file.mkv # interrupt recording with Ctrl+C ``` diff --git a/app/src/main.c b/app/src/main.c index d7816c76..d39fcd77 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -16,7 +16,7 @@ struct args { const char *record_filename; enum recorder_format record_format; SDL_bool fullscreen; - SDL_bool no_window; + SDL_bool no_display; SDL_bool help; SDL_bool version; SDL_bool show_touches; @@ -58,8 +58,9 @@ static void usage(const char *arg0) { " is preserved.\n" " Default is %d%s.\n" "\n" - " -n, --no-window\n" - " Do not show window (only when screen recording is enabled).\n" + " -N, --no-display\n" + " Do not display device (only when screen recording is\n" + " enabled).\n" "\n" " -p, --port port\n" " Set the TCP port the client listens on.\n" @@ -276,7 +277,7 @@ parse_args(struct args *args, int argc, char *argv[]) { {"fullscreen", no_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"max-size", required_argument, NULL, 'm'}, - {"no-window", no_argument, NULL, 'n'}, + {"no-display", no_argument, NULL, 'N'}, {"port", required_argument, NULL, 'p'}, {"record", required_argument, NULL, 'r'}, {"record-format", required_argument, NULL, 'f'}, @@ -286,7 +287,7 @@ parse_args(struct args *args, int argc, char *argv[]) { {NULL, 0, NULL, 0 }, }; int c; - while ((c = getopt_long(argc, argv, "b:c:fF:hm:np:r:s:tTv", long_options, + while ((c = getopt_long(argc, argv, "b:c:fF:hm:Np:r:s:tTv", long_options, NULL)) != -1) { switch (c) { case 'b': @@ -313,8 +314,8 @@ parse_args(struct args *args, int argc, char *argv[]) { return SDL_FALSE; } break; - case 'n': - args->no_window = SDL_TRUE; + case 'N': + args->no_display = SDL_TRUE; break; case 'p': if (!parse_port(optarg, &args->port)) { @@ -342,13 +343,13 @@ parse_args(struct args *args, int argc, char *argv[]) { } } - if (args->no_window && !args->record_filename) { - LOGE("-n/--no-window requires screen recording (-r/--record)"); + if (args->no_display && !args->record_filename) { + LOGE("-N/--no-display requires screen recording (-r/--record)"); return SDL_FALSE; } - if (args->no_window && args->fullscreen) { - LOGE("-f/--fullscreen-window is incompatible with -n/--no-window"); + if (args->no_display && args->fullscreen) { + LOGE("-f/--fullscreen-window is incompatible with -N/--no-display"); return SDL_FALSE; } @@ -395,7 +396,7 @@ main(int argc, char *argv[]) { .max_size = DEFAULT_MAX_SIZE, .bit_rate = DEFAULT_BIT_RATE, .always_on_top = SDL_FALSE, - .no_window = SDL_FALSE, + .no_display = SDL_FALSE, }; if (!parse_args(&args, argc, argv)) { return 1; @@ -434,7 +435,7 @@ main(int argc, char *argv[]) { .show_touches = args.show_touches, .fullscreen = args.fullscreen, .always_on_top = args.always_on_top, - .no_window = args.no_window, + .no_display = args.no_display, }; int res = scrcpy(&options) ? 0 : 1; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 03d24bc7..11349807 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -247,7 +247,7 @@ scrcpy(const struct scrcpy_options *options) { goto finally_destroy_server; } - SDL_bool display = !options->no_window; + SDL_bool display = !options->no_display; struct decoder *dec = NULL; if (display) { diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index ee3160cd..7f4fc313 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -15,7 +15,7 @@ struct scrcpy_options { SDL_bool show_touches; SDL_bool fullscreen; SDL_bool always_on_top; - SDL_bool no_window; + SDL_bool no_display; }; SDL_bool From 8655ba7197d7559695ad189a66e455261876c6f7 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 22:40:51 +0100 Subject: [PATCH 18/24] Add option to mirror in read-only Add an option to disable device control: -n/--no-control. --- README.md | 11 +++++++++ app/src/input_manager.c | 47 ++++++++++++++++++++++++------------- app/src/input_manager.h | 1 + app/src/main.c | 12 +++++++++- app/src/scrcpy.c | 52 +++++++++++++++++++++++++++++------------ app/src/scrcpy.h | 1 + 6 files changed, 92 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index a36c81f8..ab0c472f 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,17 @@ _scrcpy_ window. There is no visual feedback, a log is printed to the console. +### Read-only + +To disable controls (everything which can interact with the device: input keys, +mouse events, drag&drop files): + +```bash +scrcpy --no-control +scrcpy -n +``` + + ### Forward audio Audio is not forwarded by _scrcpy_. diff --git a/app/src/input_manager.c b/app/src/input_manager.c index f76618d0..33b5b0d3 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -202,6 +202,9 @@ input_manager_process_key(struct input_manager *input_manager, return; } + // false if the user requested not to interact with the device + SDL_bool control = input_manager->control; + // capture all Ctrl events if (ctrl | meta) { SDL_Keycode keycode = event->keysym.sym; @@ -210,36 +213,36 @@ input_manager_process_key(struct input_manager *input_manager, SDL_bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT); switch (keycode) { case SDLK_h: - if (ctrl && !meta && !shift && !repeat) { + if (control && ctrl && !meta && !shift && !repeat) { action_home(input_manager->controller, action); } return; case SDLK_b: // fall-through case SDLK_BACKSPACE: - if (ctrl && !meta && !shift && !repeat) { + if (control && ctrl && !meta && !shift && !repeat) { action_back(input_manager->controller, action); } return; case SDLK_s: - if (ctrl && !meta && !shift && !repeat) { + if (control && ctrl && !meta && !shift && !repeat) { action_app_switch(input_manager->controller, action); } return; case SDLK_m: - if (ctrl && !meta && !shift && !repeat) { + if (control && ctrl && !meta && !shift && !repeat) { action_menu(input_manager->controller, action); } return; case SDLK_p: - if (ctrl && !meta && !shift && !repeat) { + if (control && ctrl && !meta && !shift && !repeat) { action_power(input_manager->controller, action); } return; case SDLK_DOWN: #ifdef __APPLE__ - if (!ctrl && meta && !shift) { + if (control && !ctrl && meta && !shift) { #else - if (ctrl && !meta && !shift) { + if (control && ctrl && !meta && !shift) { #endif // forward repeated events action_volume_down(input_manager->controller, action); @@ -247,16 +250,16 @@ input_manager_process_key(struct input_manager *input_manager, return; case SDLK_UP: #ifdef __APPLE__ - if (!ctrl && meta && !shift) { + if (control && !ctrl && meta && !shift) { #else - if (ctrl && !meta && !shift) { + if (control && ctrl && !meta && !shift) { #endif // forward repeated events action_volume_up(input_manager->controller, action); } return; case SDLK_v: - if (ctrl && !meta && !shift && !repeat + if (control && ctrl && !meta && !shift && !repeat && event->type == SDL_KEYDOWN) { clipboard_paste(input_manager->controller); } @@ -286,7 +289,8 @@ input_manager_process_key(struct input_manager *input_manager, } return; case SDLK_n: - if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) { + if (control && ctrl && !meta + && !repeat && event->type == SDL_KEYDOWN) { if (shift) { collapse_notification_panel(input_manager->controller); } else { @@ -299,6 +303,10 @@ input_manager_process_key(struct input_manager *input_manager, return; } + if (!control) { + return; + } + struct control_event control_event; if (input_key_from_sdl_to_android(event, &control_event)) { if (!controller_push_event(input_manager->controller, &control_event)) { @@ -334,20 +342,23 @@ is_outside_device_screen(struct input_manager *input_manager, int x, int y) void input_manager_process_mouse_button(struct input_manager *input_manager, const SDL_MouseButtonEvent *event) { + // false if the user requested not to interact with the device + SDL_bool control = input_manager->control; + if (event->type == SDL_MOUSEBUTTONDOWN) { - if (event->button == SDL_BUTTON_RIGHT) { + if (control && event->button == SDL_BUTTON_RIGHT) { press_back_or_turn_screen_on(input_manager->controller); return; } - if (event->button == SDL_BUTTON_MIDDLE) { + if (control && event->button == SDL_BUTTON_MIDDLE) { action_home(input_manager->controller, ACTION_DOWN | ACTION_UP); return; } // double-click on black borders resize to fit the device screen if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) { - SDL_bool outside= is_outside_device_screen(input_manager, - event->x, - event->y); + SDL_bool outside = is_outside_device_screen(input_manager, + event->x, + event->y); if (outside) { screen_resize_to_fit(input_manager->screen); return; @@ -356,6 +367,10 @@ input_manager_process_mouse_button(struct input_manager *input_manager, // otherwise, send the click event to the device } + if (!control) { + return; + } + struct control_event control_event; if (mouse_button_from_sdl_to_android(event, input_manager->screen->frame_size, diff --git a/app/src/input_manager.h b/app/src/input_manager.h index 62923e1e..28a9a879 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -11,6 +11,7 @@ struct input_manager { struct controller *controller; struct video_buffer *video_buffer; struct screen *screen; + SDL_bool control; }; void diff --git a/app/src/main.c b/app/src/main.c index d39fcd77..a4d705ce 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -16,6 +16,7 @@ struct args { const char *record_filename; enum recorder_format record_format; SDL_bool fullscreen; + SDL_bool no_control; SDL_bool no_display; SDL_bool help; SDL_bool version; @@ -58,6 +59,9 @@ static void usage(const char *arg0) { " is preserved.\n" " Default is %d%s.\n" "\n" + " -n, --no-control\n" + " Disable device control (mirror the device in read-only).\n" + "\n" " -N, --no-display\n" " Do not display device (only when screen recording is\n" " enabled).\n" @@ -277,6 +281,7 @@ parse_args(struct args *args, int argc, char *argv[]) { {"fullscreen", no_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"max-size", required_argument, NULL, 'm'}, + {"no-control", no_argument, NULL, 'n'}, {"no-display", no_argument, NULL, 'N'}, {"port", required_argument, NULL, 'p'}, {"record", required_argument, NULL, 'r'}, @@ -287,7 +292,7 @@ parse_args(struct args *args, int argc, char *argv[]) { {NULL, 0, NULL, 0 }, }; int c; - while ((c = getopt_long(argc, argv, "b:c:fF:hm:Np:r:s:tTv", long_options, + while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:tTv", long_options, NULL)) != -1) { switch (c) { case 'b': @@ -314,6 +319,9 @@ parse_args(struct args *args, int argc, char *argv[]) { return SDL_FALSE; } break; + case 'n': + args->no_control = SDL_TRUE; + break; case 'N': args->no_display = SDL_TRUE; break; @@ -396,6 +404,7 @@ main(int argc, char *argv[]) { .max_size = DEFAULT_MAX_SIZE, .bit_rate = DEFAULT_BIT_RATE, .always_on_top = SDL_FALSE, + .no_control = SDL_FALSE, .no_display = SDL_FALSE, }; if (!parse_args(&args, argc, argv)) { @@ -435,6 +444,7 @@ main(int argc, char *argv[]) { .show_touches = args.show_touches, .fullscreen = args.fullscreen, .always_on_top = args.always_on_top, + .no_control = args.no_control, .no_display = args.no_display, }; int res = scrcpy(&options) ? 0 : 1; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 11349807..15ffdd32 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -39,6 +39,7 @@ static struct input_manager input_manager = { .controller = &controller, .video_buffer = &video_buffer, .screen = &screen, + .control = SDL_TRUE, }; #if defined(__APPLE__) || defined(__WINDOWS__) @@ -75,7 +76,7 @@ enum event_result { }; static enum event_result -handle_event(SDL_Event *event) { +handle_event(SDL_Event *event, SDL_bool control) { switch (event->type) { case EVENT_STREAM_STOPPED: LOGD("Video stream stopped"); @@ -102,23 +103,39 @@ handle_event(SDL_Event *event) { } break; case SDL_TEXTINPUT: + if (!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 (!control) { + break; + } input_manager_process_mouse_motion(&input_manager, &event->motion); break; case SDL_MOUSEWHEEL: + if (!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_DROPFILE: { + if (!control) { + break; + } file_handler_action_t action; if (is_apk(event->drop.file)) { action = ACTION_INSTALL_APK; @@ -133,7 +150,7 @@ handle_event(SDL_Event *event) { } static SDL_bool -event_loop(SDL_bool display) { +event_loop(SDL_bool display, SDL_bool control) { #ifdef CONTINUOUS_RESIZING_WORKAROUND if (display) { SDL_AddEventWatch(event_watcher, NULL); @@ -141,7 +158,7 @@ event_loop(SDL_bool display) { #endif SDL_Event event; while (SDL_WaitEvent(&event)) { - enum event_result result = handle_event(&event); + enum event_result result = handle_event(&event, control); switch (result) { case EVENT_RESULT_STOPPED_BY_USER: return SDL_TRUE; @@ -248,6 +265,9 @@ scrcpy(const struct scrcpy_options *options) { } SDL_bool display = !options->no_display; + SDL_bool control = !options->no_control; + + input_manager.control = control; struct decoder *dec = NULL; if (display) { @@ -257,7 +277,7 @@ scrcpy(const struct scrcpy_options *options) { goto finally_destroy_server; } - if (!file_handler_init(&file_handler, server.serial)) { + if (control && !file_handler_init(&file_handler, server.serial)) { ret = SDL_FALSE; server_stop(&server); goto finally_destroy_video_buffer; @@ -293,14 +313,16 @@ scrcpy(const struct scrcpy_options *options) { } if (display) { - if (!controller_init(&controller, device_socket)) { - ret = SDL_FALSE; - goto finally_stop_stream; - } + if (control) { + if (!controller_init(&controller, device_socket)) { + ret = SDL_FALSE; + goto finally_stop_stream; + } - if (!controller_start(&controller)) { - ret = SDL_FALSE; - goto finally_destroy_controller; + if (!controller_start(&controller)) { + ret = SDL_FALSE; + goto finally_destroy_controller; + } } if (!screen_init_rendering(&screen, device_name, frame_size, @@ -319,18 +341,18 @@ scrcpy(const struct scrcpy_options *options) { show_touches_waited = SDL_TRUE; } - ret = event_loop(display); + ret = event_loop(display, control); LOGD("quit..."); screen_destroy(&screen); finally_stop_and_join_controller: - if (display) { + if (display && control) { controller_stop(&controller); controller_join(&controller); } finally_destroy_controller: - if (display) { + if (display && control) { controller_destroy(&controller); } finally_stop_stream: @@ -343,7 +365,7 @@ finally_destroy_recorder: recorder_destroy(&recorder); } finally_destroy_file_handler: - if (display) { + if (display && control) { file_handler_stop(&file_handler); file_handler_join(&file_handler); file_handler_destroy(&file_handler); diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index 7f4fc313..f5b6be26 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -15,6 +15,7 @@ struct scrcpy_options { SDL_bool show_touches; SDL_bool fullscreen; SDL_bool always_on_top; + SDL_bool no_control; SDL_bool no_display; }; From dfed1b250e5aada1c0b4c75fbaf54aebc19a92d5 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 2 Mar 2019 23:52:22 +0100 Subject: [PATCH 19/24] Replace SDL types by C99 standard types Scrcpy is a C11 project. Use the C99 standard types instead of the SDL-specific types: SDL_bool -> bool SintXX -> intXX_t UintXX -> uintXX_t --- app/src/buffer_util.h | 19 +++--- app/src/command.c | 8 +-- app/src/command.h | 8 +-- app/src/common.h | 10 +-- app/src/control_event.c | 29 +++++---- app/src/control_event.h | 17 ++--- app/src/controller.c | 35 ++++++----- app/src/controller.h | 10 +-- app/src/convert.c | 40 ++++++------ app/src/convert.h | 11 ++-- app/src/decoder.c | 20 +++--- app/src/decoder.h | 6 +- app/src/device.c | 6 +- app/src/device.h | 4 +- app/src/file_handler.c | 58 ++++++++--------- app/src/file_handler.h | 13 ++-- app/src/fps_counter.c | 10 +-- app/src/fps_counter.h | 7 ++- app/src/input_manager.c | 18 +++--- app/src/input_manager.h | 4 +- app/src/main.c | 126 +++++++++++++++++++------------------ app/src/net.c | 6 +- app/src/net.h | 13 ++-- app/src/recorder.c | 36 +++++------ app/src/recorder.h | 10 +-- app/src/scrcpy.c | 64 +++++++++---------- app/src/scrcpy.h | 21 ++++--- app/src/screen.c | 59 ++++++++--------- app/src/screen.h | 21 ++++--- app/src/server.c | 63 +++++++++---------- app/src/server.h | 23 ++++--- app/src/stream.c | 24 +++---- app/src/stream.h | 7 ++- app/src/sys/unix/command.c | 4 +- app/src/sys/unix/net.c | 8 +-- app/src/sys/win/command.c | 4 +- app/src/sys/win/net.c | 8 +-- app/src/tiny_xpm.c | 34 +++++----- app/src/video_buffer.c | 20 +++--- app/src/video_buffer.h | 10 +-- 40 files changed, 456 insertions(+), 438 deletions(-) diff --git a/app/src/buffer_util.h b/app/src/buffer_util.h index 9b2f0780..5d94deef 100644 --- a/app/src/buffer_util.h +++ b/app/src/buffer_util.h @@ -1,32 +1,33 @@ #ifndef BUFFER_UTIL_H #define BUFFER_UTIL_H -#include +#include +#include static inline void -buffer_write16be(Uint8 *buf, Uint16 value) { +buffer_write16be(uint8_t *buf, uint16_t value) { buf[0] = value >> 8; buf[1] = value; } static inline void -buffer_write32be(Uint8 *buf, Uint32 value) { +buffer_write32be(uint8_t *buf, uint32_t value) { buf[0] = value >> 24; buf[1] = value >> 16; buf[2] = value >> 8; buf[3] = value; } -static inline Uint32 -buffer_read32be(Uint8 *buf) { +static inline uint32_t +buffer_read32be(uint8_t *buf) { return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; } static inline -Uint64 buffer_read64be(Uint8 *buf) { - Uint32 msb = buffer_read32be(buf); - Uint32 lsb = buffer_read32be(&buf[4]); - return ((Uint64) msb << 32) | lsb; +uint64_t buffer_read64be(uint8_t *buf) { + uint32_t msb = buffer_read32be(buf); + uint32_t lsb = buffer_read32be(&buf[4]); + return ((uint64_t) msb << 32) | lsb; } #endif diff --git a/app/src/command.c b/app/src/command.c index 01f82344..2e116ac8 100644 --- a/app/src/command.c +++ b/app/src/command.c @@ -146,11 +146,11 @@ adb_install(const char *serial, const char *local) { return proc; } -SDL_bool +bool process_check_success(process_t proc, const char *name) { if (proc == PROCESS_NONE) { LOGE("Could not execute \"%s\"", name); - return SDL_FALSE; + return false; } exit_code_t exit_code; if (!cmd_simple_wait(proc, &exit_code)) { @@ -159,7 +159,7 @@ process_check_success(process_t proc, const char *name) { } else { LOGE("\"%s\" exited unexpectedly", name); } - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } diff --git a/app/src/command.h b/app/src/command.h index 835fce25..6681f5ea 100644 --- a/app/src/command.h +++ b/app/src/command.h @@ -1,8 +1,8 @@ #ifndef COMMAND_H #define COMMAND_H +#include #include -#include #ifdef _WIN32 @@ -42,10 +42,10 @@ enum process_result { enum process_result cmd_execute(const char *path, const char *const argv[], process_t *process); -SDL_bool +bool cmd_terminate(process_t pid); -SDL_bool +bool cmd_simple_wait(process_t pid, exit_code_t *exit_code); process_t @@ -73,7 +73,7 @@ adb_install(const char *serial, const char *local); // convenience function to wait for a successful process execution // automatically log process errors with the provided process name -SDL_bool +bool process_check_success(process_t process, const char *name); #endif diff --git a/app/src/common.h b/app/src/common.h index 133f09f5..8963f058 100644 --- a/app/src/common.h +++ b/app/src/common.h @@ -1,20 +1,20 @@ #ifndef COMMON_H #define COMMON_H -#include +#include #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) #define MIN(X,Y) (X) < (Y) ? (X) : (Y) #define MAX(X,Y) (X) > (Y) ? (X) : (Y) struct size { - Uint16 width; - Uint16 height; + uint16_t width; + uint16_t height; }; struct point { - Sint32 x; - Sint32 y; + int32_t x; + int32_t y; }; struct position { diff --git a/app/src/control_event.c b/app/src/control_event.c index 9ed69b71..40de6efc 100644 --- a/app/src/control_event.c +++ b/app/src/control_event.c @@ -1,6 +1,5 @@ #include "control_event.h" -#include #include #include "buffer_util.h" @@ -8,7 +7,7 @@ #include "log.h" static void -write_position(Uint8 *buf, const struct position *position) { +write_position(uint8_t *buf, const struct position *position) { buffer_write32be(&buf[0], position->point.x); buffer_write32be(&buf[4], position->point.y); buffer_write16be(&buf[8], position->screen_size.width); @@ -31,7 +30,7 @@ control_event_serialize(const struct control_event *event, unsigned char *buf) { // injecting a text takes time, so limit the text length len = TEXT_MAX_LENGTH; } - buffer_write16be(&buf[1], (Uint16) len); + buffer_write16be(&buf[1], (uint16_t) len); memcpy(&buf[3], event->text_event.text, len); return 3 + len; } @@ -42,8 +41,8 @@ control_event_serialize(const struct control_event *event, unsigned char *buf) { return 18; case CONTROL_EVENT_TYPE_SCROLL: write_position(&buf[1], &event->scroll_event.position); - buffer_write32be(&buf[13], (Uint32) event->scroll_event.hscroll); - buffer_write32be(&buf[17], (Uint32) event->scroll_event.vscroll); + buffer_write32be(&buf[13], (uint32_t) event->scroll_event.hscroll); + buffer_write32be(&buf[17], (uint32_t) event->scroll_event.vscroll); return 21; case CONTROL_EVENT_TYPE_COMMAND: buf[1] = event->command_event.action; @@ -61,22 +60,22 @@ control_event_destroy(struct control_event *event) { } } -SDL_bool +bool control_event_queue_is_empty(const struct control_event_queue *queue) { return queue->head == queue->tail; } -SDL_bool +bool control_event_queue_is_full(const struct control_event_queue *queue) { return (queue->head + 1) % CONTROL_EVENT_QUEUE_SIZE == queue->tail; } -SDL_bool +bool control_event_queue_init(struct control_event_queue *queue) { queue->head = 0; queue->tail = 0; // the current implementation may not fail - return SDL_TRUE; + return true; } void @@ -88,24 +87,24 @@ control_event_queue_destroy(struct control_event_queue *queue) { } } -SDL_bool +bool control_event_queue_push(struct control_event_queue *queue, const struct control_event *event) { if (control_event_queue_is_full(queue)) { - return SDL_FALSE; + return false; } queue->data[queue->head] = *event; queue->head = (queue->head + 1) % CONTROL_EVENT_QUEUE_SIZE; - return SDL_TRUE; + return true; } -SDL_bool +bool control_event_queue_take(struct control_event_queue *queue, struct control_event *event) { if (control_event_queue_is_empty(queue)) { - return SDL_FALSE; + return false; } *event = queue->data[queue->tail]; queue->tail = (queue->tail + 1) % CONTROL_EVENT_QUEUE_SIZE; - return SDL_TRUE; + return true; } diff --git a/app/src/control_event.h b/app/src/control_event.h index 18294ef8..2a33244b 100644 --- a/app/src/control_event.h +++ b/app/src/control_event.h @@ -1,8 +1,9 @@ #ifndef CONTROLEVENT_H #define CONTROLEVENT_H +#include +#include #include -#include #include "android/input.h" #include "android/keycodes.h" @@ -44,8 +45,8 @@ struct control_event { } mouse_event; struct { struct position position; - Sint32 hscroll; - Sint32 vscroll; + int32_t hscroll; + int32_t vscroll; } scroll_event; struct { enum control_event_command action; @@ -63,24 +64,24 @@ struct control_event_queue { int control_event_serialize(const struct control_event *event, unsigned char *buf); -SDL_bool +bool control_event_queue_init(struct control_event_queue *queue); void control_event_queue_destroy(struct control_event_queue *queue); -SDL_bool +bool control_event_queue_is_empty(const struct control_event_queue *queue); -SDL_bool +bool control_event_queue_is_full(const struct control_event_queue *queue); // event is copied, the queue does not use the event after the function returns -SDL_bool +bool control_event_queue_push(struct control_event_queue *queue, const struct control_event *event); -SDL_bool +bool control_event_queue_take(struct control_event_queue *queue, struct control_event *event); diff --git a/app/src/controller.c b/app/src/controller.c index 89be7e98..8b95e88c 100644 --- a/app/src/controller.c +++ b/app/src/controller.c @@ -1,29 +1,30 @@ #include "controller.h" #include + #include "config.h" #include "lock_util.h" #include "log.h" -SDL_bool +bool controller_init(struct controller *controller, socket_t video_socket) { if (!control_event_queue_init(&controller->queue)) { - return SDL_FALSE; + return false; } if (!(controller->mutex = SDL_CreateMutex())) { - return SDL_FALSE; + return false; } if (!(controller->event_cond = SDL_CreateCond())) { SDL_DestroyMutex(controller->mutex); - return SDL_FALSE; + return false; } controller->video_socket = video_socket; - controller->stopped = SDL_FALSE; + controller->stopped = false; - return SDL_TRUE; + return true; } void @@ -33,12 +34,12 @@ controller_destroy(struct controller *controller) { control_event_queue_destroy(&controller->queue); } -SDL_bool +bool controller_push_event(struct controller *controller, const struct control_event *event) { - SDL_bool res; + bool res; mutex_lock(controller->mutex); - SDL_bool was_empty = control_event_queue_is_empty(&controller->queue); + bool was_empty = control_event_queue_is_empty(&controller->queue); res = control_event_queue_push(&controller->queue, event); if (was_empty) { cond_signal(controller->event_cond); @@ -47,13 +48,13 @@ controller_push_event(struct controller *controller, return res; } -static SDL_bool +static bool process_event(struct controller *controller, const struct control_event *event) { unsigned char serialized_event[SERIALIZED_EVENT_MAX_SIZE]; int length = control_event_serialize(event, serialized_event); if (!length) { - return SDL_FALSE; + return false; } int w = net_send_all(controller->video_socket, serialized_event, length); return w == length; @@ -75,12 +76,12 @@ run_controller(void *data) { break; } struct control_event event; - SDL_bool non_empty = control_event_queue_take(&controller->queue, + bool non_empty = control_event_queue_take(&controller->queue, &event); SDL_assert(non_empty); mutex_unlock(controller->mutex); - SDL_bool ok = process_event(controller, &event); + bool ok = process_event(controller, &event); control_event_destroy(&event); if (!ok) { LOGD("Cannot write event to socket"); @@ -90,7 +91,7 @@ run_controller(void *data) { return 0; } -SDL_bool +bool controller_start(struct controller *controller) { LOGD("Starting controller thread"); @@ -98,16 +99,16 @@ controller_start(struct controller *controller) { controller); if (!controller->thread) { LOGC("Could not start controller thread"); - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } void controller_stop(struct controller *controller) { mutex_lock(controller->mutex); - controller->stopped = SDL_TRUE; + controller->stopped = true; cond_signal(controller->event_cond); mutex_unlock(controller->mutex); } diff --git a/app/src/controller.h b/app/src/controller.h index 5afebc82..2f7696e3 100644 --- a/app/src/controller.h +++ b/app/src/controller.h @@ -3,8 +3,8 @@ #include "control_event.h" +#include #include -#include #include #include "net.h" @@ -14,17 +14,17 @@ struct controller { SDL_Thread *thread; SDL_mutex *mutex; SDL_cond *event_cond; - SDL_bool stopped; + bool stopped; struct control_event_queue queue; }; -SDL_bool +bool controller_init(struct controller *controller, socket_t video_socket); void controller_destroy(struct controller *controller); -SDL_bool +bool controller_start(struct controller *controller); void @@ -34,7 +34,7 @@ void controller_join(struct controller *controller); // expose simple API to hide control_event_queue -SDL_bool +bool controller_push_event(struct controller *controller, const struct control_event *event); diff --git a/app/src/convert.c b/app/src/convert.c index 6bdd9631..d20e255f 100644 --- a/app/src/convert.c +++ b/app/src/convert.c @@ -1,9 +1,9 @@ #include "convert.h" -#define MAP(FROM, TO) case FROM: *to = TO; return SDL_TRUE -#define FAIL default: return SDL_FALSE +#define MAP(FROM, TO) case FROM: *to = TO; return true +#define FAIL default: return false -static SDL_bool +static bool convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to) { switch (from) { MAP(SDL_KEYDOWN, AKEY_EVENT_ACTION_DOWN); @@ -73,8 +73,8 @@ convert_meta_state(SDL_Keymod mod) { return autocomplete_metastate(metastate); } -static SDL_bool -convert_keycode(SDL_Keycode from, enum android_keycode *to, Uint16 mod) { +static bool +convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) { switch (from) { MAP(SDLK_RETURN, AKEYCODE_ENTER); MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER); @@ -92,7 +92,7 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, Uint16 mod) { MAP(SDLK_UP, AKEYCODE_DPAD_UP); } if (mod & (KMOD_LALT | KMOD_RALT | KMOD_LGUI | KMOD_RGUI)) { - return SDL_FALSE; + return false; } // if ALT and META are not pressed, also handle letters and space switch (from) { @@ -127,7 +127,7 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, Uint16 mod) { } } -static SDL_bool +static bool convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) { switch (from) { MAP(SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN); @@ -137,7 +137,7 @@ convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) { } static enum android_motionevent_buttons -convert_mouse_buttons(Uint32 state) { +convert_mouse_buttons(uint32_t state) { enum android_motionevent_buttons buttons = 0; if (state & SDL_BUTTON_LMASK) { buttons |= AMOTION_EVENT_BUTTON_PRIMARY; @@ -157,33 +157,33 @@ convert_mouse_buttons(Uint32 state) { return buttons; } -SDL_bool +bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from, struct control_event *to) { to->type = CONTROL_EVENT_TYPE_KEYCODE; if (!convert_keycode_action(from->type, &to->keycode_event.action)) { - return SDL_FALSE; + return false; } - Uint16 mod = from->keysym.mod; + uint16_t mod = from->keysym.mod; if (!convert_keycode(from->keysym.sym, &to->keycode_event.keycode, mod)) { - return SDL_FALSE; + return false; } to->keycode_event.metastate = convert_meta_state(mod); - return SDL_TRUE; + return true; } -SDL_bool +bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, struct size screen_size, struct control_event *to) { to->type = CONTROL_EVENT_TYPE_MOUSE; if (!convert_mouse_action(from->type, &to->mouse_event.action)) { - return SDL_FALSE; + return false; } to->mouse_event.buttons = convert_mouse_buttons(SDL_BUTTON(from->button)); @@ -191,10 +191,10 @@ mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, to->mouse_event.position.point.x = from->x; to->mouse_event.position.point.y = from->y; - return SDL_TRUE; + return true; } -SDL_bool +bool mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, struct size screen_size, struct control_event *to) { @@ -205,10 +205,10 @@ mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, to->mouse_event.position.point.x = from->x; to->mouse_event.position.point.y = from->y; - return SDL_TRUE; + return true; } -SDL_bool +bool mouse_wheel_from_sdl_to_android(const SDL_MouseWheelEvent *from, struct position position, struct control_event *to) { @@ -223,5 +223,5 @@ mouse_wheel_from_sdl_to_android(const SDL_MouseWheelEvent *from, to->scroll_event.hscroll = -mul * from->x; to->scroll_event.vscroll = mul * from->y; - return SDL_TRUE; + return true; } diff --git a/app/src/convert.h b/app/src/convert.h index edd3e0fa..22cf1023 100644 --- a/app/src/convert.h +++ b/app/src/convert.h @@ -1,8 +1,9 @@ #ifndef CONVERT_H #define CONVERT_H -#include +#include #include + #include "control_event.h" struct complete_mouse_motion_event { @@ -15,24 +16,24 @@ struct complete_mouse_wheel_event { struct point position; }; -SDL_bool +bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from, struct control_event *to); -SDL_bool +bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from, struct size screen_size, struct control_event *to); // the video size may be different from the real device size, so we need the // size to which the absolute position apply, to scale it accordingly -SDL_bool +bool mouse_motion_from_sdl_to_android(const SDL_MouseMotionEvent *from, struct size screen_size, struct control_event *to); // on Android, a scroll event requires the current mouse position -SDL_bool +bool mouse_wheel_from_sdl_to_android(const SDL_MouseWheelEvent *from, struct position position, struct control_event *to); diff --git a/app/src/decoder.c b/app/src/decoder.c index 84886c9d..59bd94ce 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -20,7 +20,7 @@ // set the decoded frame as ready for rendering, and notify static void push_frame(struct decoder *decoder) { - SDL_bool previous_frame_consumed = + bool previous_frame_consumed = video_buffer_offer_decoded_frame(decoder->video_buffer); if (!previous_frame_consumed) { // the previous EVENT_NEW_FRAME will consume this frame @@ -37,21 +37,21 @@ decoder_init(struct decoder *decoder, struct video_buffer *vb) { decoder->video_buffer = vb; } -SDL_bool +bool decoder_open(struct decoder *decoder, AVCodec *codec) { decoder->codec_ctx = avcodec_alloc_context3(codec); if (!decoder->codec_ctx) { LOGC("Could not allocate decoder context"); - return SDL_FALSE; + return false; } if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) { LOGE("Could not open codec"); avcodec_free_context(&decoder->codec_ctx); - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } void @@ -60,7 +60,7 @@ decoder_close(struct decoder *decoder) { avcodec_free_context(&decoder->codec_ctx); } -SDL_bool +bool decoder_push(struct decoder *decoder, AVPacket *packet) { // the new decoding/encoding API has been introduced by: // @@ -68,7 +68,7 @@ decoder_push(struct decoder *decoder, AVPacket *packet) { int ret; if ((ret = avcodec_send_packet(decoder->codec_ctx, packet)) < 0) { LOGE("Could not send video packet: %d", ret); - return SDL_FALSE; + return false; } ret = avcodec_receive_frame(decoder->codec_ctx, decoder->video_buffer->decoding_frame); @@ -77,7 +77,7 @@ decoder_push(struct decoder *decoder, AVPacket *packet) { push_frame(decoder); } else if (ret != AVERROR(EAGAIN)) { LOGE("Could not receive video frame: %d", ret); - return SDL_FALSE; + return false; } #else int got_picture; @@ -87,13 +87,13 @@ decoder_push(struct decoder *decoder, AVPacket *packet) { packet); if (len < 0) { LOGE("Could not decode video packet: %d", len); - return SDL_FALSE; + return false; } if (got_picture) { push_frame(decoder); } #endif - return SDL_TRUE; + return true; } void diff --git a/app/src/decoder.h b/app/src/decoder.h index 266876c9..c6349281 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -1,8 +1,8 @@ #ifndef DECODER_H #define DECODER_H +#include #include -#include struct video_buffer; @@ -14,13 +14,13 @@ struct decoder { void decoder_init(struct decoder *decoder, struct video_buffer *vb); -SDL_bool +bool decoder_open(struct decoder *decoder, AVCodec *codec); void decoder_close(struct decoder *decoder); -SDL_bool +bool decoder_push(struct decoder *decoder, AVPacket *packet); void diff --git a/app/src/device.c b/app/src/device.c index 9c38bf12..8027ccbb 100644 --- a/app/src/device.c +++ b/app/src/device.c @@ -1,13 +1,13 @@ #include "device.h" #include "log.h" -SDL_bool +bool device_read_info(socket_t device_socket, char *device_name, struct size *size) { unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4]; int r = net_recv_all(device_socket, buf, sizeof(buf)); if (r < DEVICE_NAME_FIELD_LENGTH + 4) { LOGE("Could not retrieve device information"); - return SDL_FALSE; + return false; } // in case the client sends garbage buf[DEVICE_NAME_FIELD_LENGTH - 1] = '\0'; @@ -18,5 +18,5 @@ device_read_info(socket_t device_socket, char *device_name, struct size *size) { | buf[DEVICE_NAME_FIELD_LENGTH + 1]; size->height = (buf[DEVICE_NAME_FIELD_LENGTH + 2] << 8) | buf[DEVICE_NAME_FIELD_LENGTH + 3]; - return SDL_TRUE; + return true; } diff --git a/app/src/device.h b/app/src/device.h index bacc5355..09934046 100644 --- a/app/src/device.h +++ b/app/src/device.h @@ -1,7 +1,7 @@ #ifndef DEVICE_H #define DEVICE_H -#include +#include #include "common.h" #include "net.h" @@ -10,7 +10,7 @@ #define DEVICE_SDCARD_PATH "/sdcard/" // name must be at least DEVICE_NAME_FIELD_LENGTH bytes -SDL_bool +bool device_read_info(socket_t device_socket, char *name, struct size *frame_size); #endif diff --git a/app/src/file_handler.c b/app/src/file_handler.c index f70f61d3..d3dedcd2 100644 --- a/app/src/file_handler.c +++ b/app/src/file_handler.c @@ -33,21 +33,21 @@ request_free(struct request *req) { SDL_free((void *) req); } -static SDL_bool +static bool request_queue_is_empty(const struct request_queue *queue) { return queue->head == queue->tail; } -static SDL_bool +static bool request_queue_is_full(const struct request_queue *queue) { return (queue->head + 1) % REQUEST_QUEUE_SIZE == queue->tail; } -static SDL_bool +static bool request_queue_init(struct request_queue *queue) { queue->head = 0; queue->tail = 0; - return SDL_TRUE; + return true; } static void @@ -59,41 +59,41 @@ request_queue_destroy(struct request_queue *queue) { } } -static SDL_bool +static bool request_queue_push(struct request_queue *queue, struct request *req) { if (request_queue_is_full(queue)) { - return SDL_FALSE; + return false; } queue->reqs[queue->head] = req; queue->head = (queue->head + 1) % REQUEST_QUEUE_SIZE; - return SDL_TRUE; + return true; } -static SDL_bool +static bool request_queue_take(struct request_queue *queue, struct request **req) { if (request_queue_is_empty(queue)) { - return SDL_FALSE; + return false; } // transfer ownership *req = queue->reqs[queue->tail]; queue->tail = (queue->tail + 1) % REQUEST_QUEUE_SIZE; - return SDL_TRUE; + return true; } -SDL_bool +bool file_handler_init(struct file_handler *file_handler, const char *serial) { if (!request_queue_init(&file_handler->queue)) { - return SDL_FALSE; + return false; } if (!(file_handler->mutex = SDL_CreateMutex())) { - return SDL_FALSE; + return false; } if (!(file_handler->event_cond = SDL_CreateCond())) { SDL_DestroyMutex(file_handler->mutex); - return SDL_FALSE; + return false; } if (serial) { @@ -101,19 +101,19 @@ file_handler_init(struct file_handler *file_handler, const char *serial) { if (!file_handler->serial) { LOGW("Cannot strdup serial"); SDL_DestroyMutex(file_handler->mutex); - return SDL_FALSE; + return false; } } else { file_handler->serial = NULL; } // lazy initialization - file_handler->initialized = SDL_FALSE; + file_handler->initialized = false; - file_handler->stopped = SDL_FALSE; + file_handler->stopped = false; file_handler->current_process = PROCESS_NONE; - return SDL_TRUE; + return true; } void @@ -134,18 +134,18 @@ push_file(const char *serial, const char *file) { return adb_push(serial, file, DEVICE_SDCARD_PATH); } -SDL_bool +bool file_handler_request(struct file_handler *file_handler, file_handler_action_t action, const char *file) { - SDL_bool res; + bool res; // start file_handler if it's used for the first time if (!file_handler->initialized) { if (!file_handler_start(file_handler)) { - return SDL_FALSE; + return false; } - file_handler->initialized = SDL_TRUE; + file_handler->initialized = true; } LOGI("Request to %s %s", action == ACTION_INSTALL_APK ? "install" : "push", @@ -153,11 +153,11 @@ file_handler_request(struct file_handler *file_handler, struct request *req = request_new(action, file); if (!req) { LOGE("Could not create request"); - return SDL_FALSE; + return false; } mutex_lock(file_handler->mutex); - SDL_bool was_empty = request_queue_is_empty(&file_handler->queue); + bool was_empty = request_queue_is_empty(&file_handler->queue); res = request_queue_push(&file_handler->queue, req); if (was_empty) { cond_signal(file_handler->event_cond); @@ -183,7 +183,7 @@ run_file_handler(void *data) { break; } struct request *req; - SDL_bool non_empty = request_queue_take(&file_handler->queue, &req); + bool non_empty = request_queue_take(&file_handler->queue, &req); SDL_assert(non_empty); process_t process; @@ -216,7 +216,7 @@ run_file_handler(void *data) { return 0; } -SDL_bool +bool file_handler_start(struct file_handler *file_handler) { LOGD("Starting file_handler thread"); @@ -224,16 +224,16 @@ file_handler_start(struct file_handler *file_handler) { file_handler); if (!file_handler->thread) { LOGC("Could not start file_handler thread"); - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } void file_handler_stop(struct file_handler *file_handler) { mutex_lock(file_handler->mutex); - file_handler->stopped = SDL_TRUE; + file_handler->stopped = true; cond_signal(file_handler->event_cond); if (file_handler->current_process != PROCESS_NONE) { if (!cmd_terminate(file_handler->current_process)) { diff --git a/app/src/file_handler.h b/app/src/file_handler.h index ed1c8867..111161dc 100644 --- a/app/src/file_handler.h +++ b/app/src/file_handler.h @@ -1,9 +1,10 @@ #ifndef FILE_HANDLER_H #define FILE_HANDLER_H +#include #include -#include #include + #include "command.h" #define REQUEST_QUEUE_SIZE 16 @@ -24,19 +25,19 @@ struct file_handler { SDL_Thread *thread; SDL_mutex *mutex; SDL_cond *event_cond; - SDL_bool stopped; - SDL_bool initialized; + bool stopped; + bool initialized; process_t current_process; struct request_queue queue; }; -SDL_bool +bool file_handler_init(struct file_handler *file_handler, const char *serial); void file_handler_destroy(struct file_handler *file_handler); -SDL_bool +bool file_handler_start(struct file_handler *file_handler); void @@ -45,7 +46,7 @@ file_handler_stop(struct file_handler *file_handler); void file_handler_join(struct file_handler *file_handler); -SDL_bool +bool file_handler_request(struct file_handler *file_handler, file_handler_action_t action, const char *file); diff --git a/app/src/fps_counter.c b/app/src/fps_counter.c index fc86f22c..6c8ef795 100644 --- a/app/src/fps_counter.c +++ b/app/src/fps_counter.c @@ -6,14 +6,14 @@ void fps_counter_init(struct fps_counter *counter) { - counter->started = SDL_FALSE; + counter->started = false; // no need to initialize the other fields, they are meaningful only when // started is true } void fps_counter_start(struct fps_counter *counter) { - counter->started = SDL_TRUE; + counter->started = true; counter->slice_start = SDL_GetTicks(); counter->nr_rendered = 0; #ifdef SKIP_FRAMES @@ -23,7 +23,7 @@ fps_counter_start(struct fps_counter *counter) { void fps_counter_stop(struct fps_counter *counter) { - counter->started = SDL_FALSE; + counter->started = false; } static void @@ -42,11 +42,11 @@ display_fps(struct fps_counter *counter) { static void check_expired(struct fps_counter *counter) { - Uint32 now = SDL_GetTicks(); + uint32_t now = SDL_GetTicks(); if (now - counter->slice_start >= 1000) { display_fps(counter); // add a multiple of one second - Uint32 elapsed_slices = (now - counter->slice_start) / 1000; + uint32_t elapsed_slices = (now - counter->slice_start) / 1000; counter->slice_start += 1000 * elapsed_slices; counter->nr_rendered = 0; #ifdef SKIP_FRAMES diff --git a/app/src/fps_counter.h b/app/src/fps_counter.h index 2d48624f..dcdf10bf 100644 --- a/app/src/fps_counter.h +++ b/app/src/fps_counter.h @@ -1,13 +1,14 @@ #ifndef FPSCOUNTER_H #define FPSCOUNTER_H -#include +#include +#include #include "config.h" struct fps_counter { - SDL_bool started; - Uint32 slice_start; // initialized by SDL_GetTicks() + bool started; + uint32_t slice_start; // initialized by SDL_GetTicks() int nr_rendered; #ifdef SKIP_FRAMES int nr_skipped; diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 33b5b0d3..eb4047e9 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -192,9 +192,9 @@ input_manager_process_text_input(struct input_manager *input_manager, void input_manager_process_key(struct input_manager *input_manager, const SDL_KeyboardEvent *event) { - SDL_bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL); - SDL_bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT); - SDL_bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI); + bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL); + bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT); + bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI); if (alt) { // no shortcut involves Alt or Meta, and they should not be forwarded @@ -203,14 +203,14 @@ input_manager_process_key(struct input_manager *input_manager, } // false if the user requested not to interact with the device - SDL_bool control = input_manager->control; + bool control = input_manager->control; // capture all Ctrl events if (ctrl | meta) { SDL_Keycode keycode = event->keysym.sym; int action = event->type == SDL_KEYDOWN ? ACTION_DOWN : ACTION_UP; - SDL_bool repeat = event->repeat; - SDL_bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT); + bool repeat = event->repeat; + bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT); switch (keycode) { case SDLK_h: if (control && ctrl && !meta && !shift && !repeat) { @@ -332,7 +332,7 @@ input_manager_process_mouse_motion(struct input_manager *input_manager, } } -static SDL_bool +static bool is_outside_device_screen(struct input_manager *input_manager, int x, int y) { return x < 0 || x >= input_manager->screen->frame_size.width || @@ -343,7 +343,7 @@ void input_manager_process_mouse_button(struct input_manager *input_manager, const SDL_MouseButtonEvent *event) { // false if the user requested not to interact with the device - SDL_bool control = input_manager->control; + bool control = input_manager->control; if (event->type == SDL_MOUSEBUTTONDOWN) { if (control && event->button == SDL_BUTTON_RIGHT) { @@ -356,7 +356,7 @@ input_manager_process_mouse_button(struct input_manager *input_manager, } // double-click on black borders resize to fit the device screen if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) { - SDL_bool outside = is_outside_device_screen(input_manager, + bool outside = is_outside_device_screen(input_manager, event->x, event->y); if (outside) { diff --git a/app/src/input_manager.h b/app/src/input_manager.h index 28a9a879..c30a8188 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -1,6 +1,8 @@ #ifndef INPUTMANAGER_H #define INPUTMANAGER_H +#include + #include "common.h" #include "controller.h" #include "fps_counter.h" @@ -11,7 +13,7 @@ struct input_manager { struct controller *controller; struct video_buffer *video_buffer; struct screen *screen; - SDL_bool control; + bool control; }; void diff --git a/app/src/main.c b/app/src/main.c index a4d705ce..b2a6bf5e 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -1,6 +1,8 @@ #include "scrcpy.h" #include +#include +#include #include #include #include @@ -15,16 +17,16 @@ struct args { const char *crop; const char *record_filename; enum recorder_format record_format; - SDL_bool fullscreen; - SDL_bool no_control; - SDL_bool no_display; - SDL_bool help; - SDL_bool version; - SDL_bool show_touches; - Uint16 port; - Uint16 max_size; - Uint32 bit_rate; - SDL_bool always_on_top; + bool fullscreen; + bool no_control; + bool no_display; + bool help; + bool version; + bool show_touches; + uint16_t port; + uint16_t max_size; + uint32_t bit_rate; + bool always_on_top; }; static void usage(const char *arg0) { @@ -168,19 +170,19 @@ print_version(void) { LIBAVUTIL_VERSION_MICRO); } -static SDL_bool -parse_bit_rate(char *optarg, Uint32 *bit_rate) { +static bool +parse_bit_rate(char *optarg, uint32_t *bit_rate) { char *endptr; if (*optarg == '\0') { LOGE("Bit-rate parameter is empty"); - return SDL_FALSE; + return false; } long value = strtol(optarg, &endptr, 0); int mul = 1; if (*endptr != '\0') { if (optarg == endptr) { LOGE("Invalid bit-rate: %s", optarg); - return SDL_FALSE; + return false; } if ((*endptr == 'M' || *endptr == 'm') && endptr[1] == '\0') { mul = 1000000; @@ -188,72 +190,72 @@ parse_bit_rate(char *optarg, Uint32 *bit_rate) { mul = 1000; } else { LOGE("Invalid bit-rate unit: %s", optarg); - return SDL_FALSE; + return false; } } - if (value < 0 || ((Uint32) -1) / mul < value) { + if (value < 0 || ((uint32_t) -1) / mul < value) { LOGE("Bitrate must be positive and less than 2^32: %s", optarg); - return SDL_FALSE; + return false; } - *bit_rate = (Uint32) value * mul; - return SDL_TRUE; + *bit_rate = (uint32_t) value * mul; + return true; } -static SDL_bool -parse_max_size(char *optarg, Uint16 *max_size) { +static bool +parse_max_size(char *optarg, uint16_t *max_size) { char *endptr; if (*optarg == '\0') { LOGE("Max size parameter is empty"); - return SDL_FALSE; + return false; } long value = strtol(optarg, &endptr, 0); if (*endptr != '\0') { LOGE("Invalid max size: %s", optarg); - return SDL_FALSE; + return false; } if (value & ~0xffff) { LOGE("Max size must be between 0 and 65535: %ld", value); - return SDL_FALSE; + return false; } - *max_size = (Uint16) value; - return SDL_TRUE; + *max_size = (uint16_t) value; + return true; } -static SDL_bool -parse_port(char *optarg, Uint16 *port) { +static bool +parse_port(char *optarg, uint16_t *port) { char *endptr; if (*optarg == '\0') { LOGE("Invalid port parameter is empty"); - return SDL_FALSE; + return false; } long value = strtol(optarg, &endptr, 0); if (*endptr != '\0') { LOGE("Invalid port: %s", optarg); - return SDL_FALSE; + return false; } if (value & ~0xffff) { LOGE("Port out of range: %ld", value); - return SDL_FALSE; + return false; } - *port = (Uint16) value; - return SDL_TRUE; + *port = (uint16_t) value; + return true; } -static SDL_bool +static bool parse_record_format(const char *optarg, enum recorder_format *format) { if (!strcmp(optarg, "mp4")) { *format = RECORDER_FORMAT_MP4; - return SDL_TRUE; + return true; } if (!strcmp(optarg, "mkv")) { *format = RECORDER_FORMAT_MKV; - return SDL_TRUE; + return true; } LOGE("Unsupported format: %s (expected mp4 or mkv)", optarg); - return SDL_FALSE; + return false; } static enum recorder_format @@ -272,7 +274,7 @@ guess_record_format(const char *filename) { return 0; } -static SDL_bool +static bool parse_args(struct args *args, int argc, char *argv[]) { static const struct option long_options[] = { {"always-on-top", no_argument, NULL, 'T'}, @@ -297,37 +299,37 @@ parse_args(struct args *args, int argc, char *argv[]) { switch (c) { case 'b': if (!parse_bit_rate(optarg, &args->bit_rate)) { - return SDL_FALSE; + return false; } break; case 'c': args->crop = optarg; break; case 'f': - args->fullscreen = SDL_TRUE; + args->fullscreen = true; break; case 'F': if (!parse_record_format(optarg, &args->record_format)) { - return SDL_FALSE; + return false; } break; case 'h': - args->help = SDL_TRUE; + args->help = true; break; case 'm': if (!parse_max_size(optarg, &args->max_size)) { - return SDL_FALSE; + return false; } break; case 'n': - args->no_control = SDL_TRUE; + args->no_control = true; break; case 'N': - args->no_display = SDL_TRUE; + args->no_display = true; break; case 'p': if (!parse_port(optarg, &args->port)) { - return SDL_FALSE; + return false; } break; case 'r': @@ -337,39 +339,39 @@ parse_args(struct args *args, int argc, char *argv[]) { args->serial = optarg; break; case 't': - args->show_touches = SDL_TRUE; + args->show_touches = true; break; case 'T': - args->always_on_top = SDL_TRUE; + args->always_on_top = true; break; case 'v': - args->version = SDL_TRUE; + args->version = true; break; default: // getopt prints the error message on stderr - return SDL_FALSE; + return false; } } if (args->no_display && !args->record_filename) { LOGE("-N/--no-display requires screen recording (-r/--record)"); - return SDL_FALSE; + return false; } if (args->no_display && args->fullscreen) { LOGE("-f/--fullscreen-window is incompatible with -N/--no-display"); - return SDL_FALSE; + return false; } int index = optind; if (index < argc) { LOGE("Unexpected additional argument: %s", argv[index]); - return SDL_FALSE; + return false; } if (args->record_format && !args->record_filename) { LOGE("Record format specified without recording"); - return SDL_FALSE; + return false; } if (args->record_filename && !args->record_format) { @@ -377,11 +379,11 @@ parse_args(struct args *args, int argc, char *argv[]) { if (!args->record_format) { LOGE("No format specified for \"%s\" (try with -F mkv)", args->record_filename); - return SDL_FALSE; + return false; } } - return SDL_TRUE; + return true; } int @@ -397,15 +399,15 @@ main(int argc, char *argv[]) { .crop = NULL, .record_filename = NULL, .record_format = 0, - .help = SDL_FALSE, - .version = SDL_FALSE, - .show_touches = SDL_FALSE, + .help = false, + .version = false, + .show_touches = false, .port = DEFAULT_LOCAL_PORT, .max_size = DEFAULT_MAX_SIZE, .bit_rate = DEFAULT_BIT_RATE, - .always_on_top = SDL_FALSE, - .no_control = SDL_FALSE, - .no_display = SDL_FALSE, + .always_on_top = false, + .no_control = false, + .no_display = false, }; if (!parse_args(&args, argc, argv)) { return 1; diff --git a/app/src/net.c b/app/src/net.c index 70fcb304..b5b227c2 100644 --- a/app/src/net.c +++ b/app/src/net.c @@ -19,7 +19,7 @@ #endif socket_t -net_connect(Uint32 addr, Uint16 port) { +net_connect(uint32_t addr, uint16_t port) { socket_t sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { perror("socket"); @@ -40,7 +40,7 @@ net_connect(Uint32 addr, Uint16 port) { } socket_t -net_listen(Uint32 addr, Uint16 port, int backlog) { +net_listen(uint32_t addr, uint16_t port, int backlog) { socket_t sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { perror("socket"); @@ -107,7 +107,7 @@ net_send_all(socket_t socket, const void *buf, size_t len) { return w; } -SDL_bool +bool net_shutdown(socket_t socket, int how) { return !shutdown(socket, how); } diff --git a/app/src/net.h b/app/src/net.h index d712e6d3..dd82c083 100644 --- a/app/src/net.h +++ b/app/src/net.h @@ -1,8 +1,9 @@ #ifndef NET_H #define NET_H +#include +#include #include -#include #ifdef __WINDOWS__ # include @@ -16,17 +17,17 @@ typedef int socket_t; #endif -SDL_bool +bool net_init(void); void net_cleanup(void); socket_t -net_connect(Uint32 addr, Uint16 port); +net_connect(uint32_t addr, uint16_t port); socket_t -net_listen(Uint32 addr, Uint16 port, int backlog); +net_listen(uint32_t addr, uint16_t port, int backlog); socket_t net_accept(socket_t server_socket); @@ -45,10 +46,10 @@ ssize_t net_send_all(socket_t socket, const void *buf, size_t len); // how is SHUT_RD (read), SHUT_WR (write) or SHUT_RDWR (both) -SDL_bool +bool net_shutdown(socket_t socket, int how); -SDL_bool +bool net_close(socket_t socket); #endif diff --git a/app/src/recorder.c b/app/src/recorder.c index db9d8a7a..2f33702d 100644 --- a/app/src/recorder.c +++ b/app/src/recorder.c @@ -26,7 +26,7 @@ find_muxer(const char *name) { return oformat; } -SDL_bool +bool recorder_init(struct recorder *recorder, const char *filename, enum recorder_format format, @@ -34,14 +34,14 @@ recorder_init(struct recorder *recorder, recorder->filename = SDL_strdup(filename); if (!recorder->filename) { LOGE("Cannot strdup filename"); - return SDL_FALSE; + return false; } recorder->format = format; recorder->declared_frame_size = declared_frame_size; - recorder->header_written = SDL_FALSE; + recorder->header_written = false; - return SDL_TRUE; + return true; } void @@ -58,20 +58,20 @@ recorder_get_format_name(enum recorder_format format) { } } -SDL_bool +bool recorder_open(struct recorder *recorder, AVCodec *input_codec) { const char *format_name = recorder_get_format_name(recorder->format); SDL_assert(format_name); const AVOutputFormat *format = find_muxer(format_name); if (!format) { LOGE("Could not find muxer"); - return SDL_FALSE; + return false; } recorder->ctx = avformat_alloc_context(); if (!recorder->ctx) { LOGE("Could not allocate output context"); - return SDL_FALSE; + return false; } // contrary to the deprecated API (av_oformat_next()), av_muxer_iterate() @@ -83,7 +83,7 @@ recorder_open(struct recorder *recorder, AVCodec *input_codec) { AVStream *ostream = avformat_new_stream(recorder->ctx, input_codec); if (!ostream) { avformat_free_context(recorder->ctx); - return SDL_FALSE; + return false; } #ifdef SCRCPY_LAVF_HAS_NEW_CODEC_PARAMS_API @@ -106,12 +106,12 @@ recorder_open(struct recorder *recorder, AVCodec *input_codec) { LOGE("Failed to open output file: %s", recorder->filename); // ostream will be cleaned up during context cleaning avformat_free_context(recorder->ctx); - return SDL_FALSE; + return false; } LOGI("Recording started to %s file: %s", format_name, recorder->filename); - return SDL_TRUE; + return true; } void @@ -127,14 +127,14 @@ recorder_close(struct recorder *recorder) { LOGI("Recording complete to %s file: %s", format_name, recorder->filename); } -static SDL_bool +static bool recorder_write_header(struct recorder *recorder, AVPacket *packet) { AVStream *ostream = recorder->ctx->streams[0]; uint8_t *extradata = av_malloc(packet->size * sizeof(uint8_t)); if (!extradata) { LOGC("Cannot allocate extradata"); - return SDL_FALSE; + return false; } // copy the first packet to the extra data @@ -154,10 +154,10 @@ recorder_write_header(struct recorder *recorder, AVPacket *packet) { SDL_free(extradata); avio_closep(&recorder->ctx->pb); avformat_free_context(recorder->ctx); - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } static void @@ -166,14 +166,14 @@ recorder_rescale_packet(struct recorder *recorder, AVPacket *packet) { av_packet_rescale_ts(packet, SCRCPY_TIME_BASE, ostream->time_base); } -SDL_bool +bool recorder_write(struct recorder *recorder, AVPacket *packet) { if (!recorder->header_written) { - SDL_bool ok = recorder_write_header(recorder, packet); + bool ok = recorder_write_header(recorder, packet); if (!ok) { - return SDL_FALSE; + return false; } - recorder->header_written = SDL_TRUE; + recorder->header_written = true; } recorder_rescale_packet(recorder, packet); diff --git a/app/src/recorder.h b/app/src/recorder.h index 5ead6f3f..c126b29b 100644 --- a/app/src/recorder.h +++ b/app/src/recorder.h @@ -1,8 +1,8 @@ #ifndef RECORDER_H #define RECORDER_H +#include #include -#include #include "common.h" @@ -16,23 +16,23 @@ struct recorder { enum recorder_format format; AVFormatContext *ctx; struct size declared_frame_size; - SDL_bool header_written; + bool header_written; }; -SDL_bool +bool recorder_init(struct recorder *recoder, const char *filename, enum recorder_format format, struct size declared_frame_size); void recorder_destroy(struct recorder *recorder); -SDL_bool +bool recorder_open(struct recorder *recorder, AVCodec *input_codec); void recorder_close(struct recorder *recorder); -SDL_bool +bool recorder_write(struct recorder *recorder, AVPacket *packet); #endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 15ffdd32..26bde219 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -39,7 +39,7 @@ static struct input_manager input_manager = { .controller = &controller, .video_buffer = &video_buffer, .screen = &screen, - .control = SDL_TRUE, + .control = true, }; #if defined(__APPLE__) || defined(__WINDOWS__) @@ -63,7 +63,7 @@ event_watcher(void *data, SDL_Event *event) { } #endif -static SDL_bool +static bool is_apk(const char *file) { const char *ext = strrchr(file, '.'); return ext && !strcmp(ext, ".apk"); @@ -76,7 +76,7 @@ enum event_result { }; static enum event_result -handle_event(SDL_Event *event, SDL_bool control) { +handle_event(SDL_Event *event, bool control) { switch (event->type) { case EVENT_STREAM_STOPPED: LOGD("Video stream stopped"); @@ -86,12 +86,12 @@ handle_event(SDL_Event *event, SDL_bool control) { return EVENT_RESULT_STOPPED_BY_USER; case EVENT_NEW_FRAME: if (!screen.has_frame) { - screen.has_frame = SDL_TRUE; + 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 SDL_FALSE; + return false; } break; case SDL_WINDOWEVENT: @@ -149,8 +149,8 @@ handle_event(SDL_Event *event, SDL_bool control) { return EVENT_RESULT_CONTINUE; } -static SDL_bool -event_loop(SDL_bool display, SDL_bool control) { +static bool +event_loop(bool display, bool control) { #ifdef CONTINUOUS_RESIZING_WORKAROUND if (display) { SDL_AddEventWatch(event_watcher, NULL); @@ -161,18 +161,18 @@ event_loop(SDL_bool display, SDL_bool control) { enum event_result result = handle_event(&event, control); switch (result) { case EVENT_RESULT_STOPPED_BY_USER: - return SDL_TRUE; + return true; case EVENT_RESULT_STOPPED_BY_EOS: - return SDL_FALSE; + return false; case EVENT_RESULT_CONTINUE: break; } } - return SDL_FALSE; + return false; } static process_t -set_show_touches_enabled(const char *serial, SDL_bool enabled) { +set_show_touches_enabled(const char *serial, bool enabled) { const char *value = enabled ? "1" : "0"; const char *const adb_cmd[] = { "shell", "settings", "put", "system", "show_touches", value @@ -221,34 +221,34 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) { SDL_free(local_fmt); } -SDL_bool +bool scrcpy(const struct scrcpy_options *options) { - SDL_bool record = !!options->record_filename; + bool record = !!options->record_filename; if (!server_start(&server, options->serial, options->port, options->max_size, options->bit_rate, options->crop, record)) { - return SDL_FALSE; + return false; } process_t proc_show_touches = PROCESS_NONE; - SDL_bool show_touches_waited; + bool show_touches_waited; if (options->show_touches) { LOGI("Enable show_touches"); - proc_show_touches = set_show_touches_enabled(options->serial, SDL_TRUE); - show_touches_waited = SDL_FALSE; + proc_show_touches = set_show_touches_enabled(options->serial, true); + show_touches_waited = false; } - SDL_bool ret = SDL_TRUE; + bool ret = true; if (!sdl_init_and_configure()) { - ret = SDL_FALSE; + ret = false; goto finally_destroy_server; } socket_t device_socket = server_connect_to(&server); if (device_socket == INVALID_SOCKET) { server_stop(&server); - ret = SDL_FALSE; + ret = false; goto finally_destroy_server; } @@ -260,12 +260,12 @@ scrcpy(const struct scrcpy_options *options) { // to be able to init the window immediately if (!device_read_info(device_socket, device_name, &frame_size)) { server_stop(&server); - ret = SDL_FALSE; + ret = false; goto finally_destroy_server; } - SDL_bool display = !options->no_display; - SDL_bool control = !options->no_control; + bool display = !options->no_display; + bool control = !options->no_control; input_manager.control = control; @@ -273,12 +273,12 @@ scrcpy(const struct scrcpy_options *options) { if (display) { if (!video_buffer_init(&video_buffer)) { server_stop(&server); - ret = SDL_FALSE; + ret = false; goto finally_destroy_server; } if (control && !file_handler_init(&file_handler, server.serial)) { - ret = SDL_FALSE; + ret = false; server_stop(&server); goto finally_destroy_video_buffer; } @@ -293,7 +293,7 @@ scrcpy(const struct scrcpy_options *options) { options->record_filename, options->record_format, frame_size)) { - ret = SDL_FALSE; + ret = false; server_stop(&server); goto finally_destroy_file_handler; } @@ -307,7 +307,7 @@ scrcpy(const struct scrcpy_options *options) { // now we consumed the header values, the socket receives the video stream // start the stream if (!stream_start(&stream)) { - ret = SDL_FALSE; + ret = false; server_stop(&server); goto finally_destroy_recorder; } @@ -315,19 +315,19 @@ scrcpy(const struct scrcpy_options *options) { if (display) { if (control) { if (!controller_init(&controller, device_socket)) { - ret = SDL_FALSE; + ret = false; goto finally_stop_stream; } if (!controller_start(&controller)) { - ret = SDL_FALSE; + ret = false; goto finally_destroy_controller; } } if (!screen_init_rendering(&screen, device_name, frame_size, options->always_on_top)) { - ret = SDL_FALSE; + ret = false; goto finally_stop_and_join_controller; } @@ -338,7 +338,7 @@ scrcpy(const struct scrcpy_options *options) { if (options->show_touches) { wait_show_touches(proc_show_touches); - show_touches_waited = SDL_TRUE; + show_touches_waited = true; } ret = event_loop(display, control); @@ -382,7 +382,7 @@ finally_destroy_server: } LOGI("Disable show_touches"); proc_show_touches = set_show_touches_enabled(options->serial, - SDL_FALSE); + false); wait_show_touches(proc_show_touches); } diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index f5b6be26..114c12a4 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -1,7 +1,8 @@ #ifndef SCRCPY_H #define SCRCPY_H -#include +#include +#include #include struct scrcpy_options { @@ -9,17 +10,17 @@ struct scrcpy_options { const char *crop; const char *record_filename; enum recorder_format record_format; - Uint16 port; - Uint16 max_size; - Uint32 bit_rate; - SDL_bool show_touches; - SDL_bool fullscreen; - SDL_bool always_on_top; - SDL_bool no_control; - SDL_bool no_display; + uint16_t port; + uint16_t max_size; + uint32_t bit_rate; + bool show_touches; + bool fullscreen; + bool always_on_top; + bool no_control; + bool no_display; }; -SDL_bool +bool scrcpy(const struct scrcpy_options *options); #endif diff --git a/app/src/screen.c b/app/src/screen.c index 5da96b93..962d5b70 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -1,8 +1,9 @@ #include "screen.h" -#include #include +#include +#include "common.h" #include "compat.h" #include "icon.xpm" #include "lock_util.h" @@ -12,11 +13,11 @@ #define DISPLAY_MARGINS 96 -SDL_bool +bool sdl_init_and_configure(void) { if (SDL_Init(SDL_INIT_VIDEO)) { LOGC("Could not initialize SDL: %s", SDL_GetError()); - return SDL_FALSE; + return false; } atexit(SDL_Quit); @@ -36,7 +37,7 @@ sdl_init_and_configure(void) { // Do not disable the screensaver when scrcpy is running SDL_EnableScreenSaver(); - return SDL_TRUE; + return true; } // get the window size in a struct size @@ -75,7 +76,7 @@ set_window_size(struct screen *screen, struct size new_size) { } // get the preferred display bounds (i.e. the screen bounds with some margins) -static SDL_bool +static bool get_preferred_display_bounds(struct size *bounds) { SDL_Rect rect; #ifdef SCRCPY_SDL_HAS_GET_DISPLAY_USABLE_BOUNDS @@ -85,12 +86,12 @@ get_preferred_display_bounds(struct size *bounds) { #endif if (GET_DISPLAY_BOUNDS(0, &rect)) { LOGW("Could not get display usable bounds: %s", SDL_GetError()); - return SDL_FALSE; + return false; } bounds->width = MAX(0, rect.w - DISPLAY_MARGINS); bounds->height = MAX(0, rect.h - DISPLAY_MARGINS); - return SDL_TRUE; + return true; } // return the optimal size of the window, with the following constraints: @@ -107,8 +108,8 @@ get_optimal_size(struct size current_size, struct size frame_size) { struct size display_size; // 32 bits because we need to multiply two 16 bits values - Uint32 w; - Uint32 h; + uint32_t w; + uint32_t h; if (!get_preferred_display_bounds(&display_size)) { // cannot get display bounds, do not constraint the size @@ -119,7 +120,7 @@ get_optimal_size(struct size current_size, struct size frame_size) { h = MIN(current_size.height, display_size.height); } - SDL_bool keep_width = frame_size.width * h > frame_size.height * w; + bool keep_width = frame_size.width * h > frame_size.height * w; if (keep_width) { // remove black borders on top and bottom h = frame_size.height * w / frame_size.width; @@ -159,13 +160,13 @@ create_texture(SDL_Renderer *renderer, struct size frame_size) { frame_size.width, frame_size.height); } -SDL_bool +bool screen_init_rendering(struct screen *screen, const char *device_name, - struct size frame_size, SDL_bool always_on_top) { + struct size frame_size, bool always_on_top) { screen->frame_size = frame_size; struct size window_size = get_initial_optimal_size(frame_size); - Uint32 window_flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; + uint32_t window_flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; #ifdef HIDPI_SUPPORT window_flags |= SDL_WINDOW_ALLOW_HIGHDPI; #endif @@ -184,7 +185,7 @@ screen_init_rendering(struct screen *screen, const char *device_name, window_flags); if (!screen->window) { LOGC("Could not create window: %s", SDL_GetError()); - return SDL_FALSE; + return false; } screen->renderer = SDL_CreateRenderer(screen->window, -1, @@ -192,21 +193,21 @@ screen_init_rendering(struct screen *screen, const char *device_name, if (!screen->renderer) { LOGC("Could not create renderer: %s", SDL_GetError()); screen_destroy(screen); - return SDL_FALSE; + return false; } if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width, frame_size.height)) { LOGE("Could not set renderer logical size: %s", SDL_GetError()); screen_destroy(screen); - return SDL_FALSE; + return false; } SDL_Surface *icon = read_xpm(icon_xpm); if (!icon) { LOGE("Could not load icon: %s", SDL_GetError()); screen_destroy(screen); - return SDL_FALSE; + return false; } SDL_SetWindowIcon(screen->window, icon); SDL_FreeSurface(icon); @@ -217,10 +218,10 @@ screen_init_rendering(struct screen *screen, const char *device_name, if (!screen->texture) { LOGC("Could not create texture: %s", SDL_GetError()); screen_destroy(screen); - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } void @@ -242,14 +243,14 @@ screen_destroy(struct screen *screen) { } // recreate the texture and resize the window if the frame size has changed -static SDL_bool +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) { if (SDL_RenderSetLogicalSize(screen->renderer, new_frame_size.width, new_frame_size.height)) { LOGE("Could not set renderer logical size: %s", SDL_GetError()); - return SDL_FALSE; + return false; } // frame dimension changed, destroy texture @@ -257,9 +258,9 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) { struct size current_size = get_window_size(screen); struct size target_size = { - (Uint32) current_size.width * new_frame_size.width + (uint32_t) current_size.width * new_frame_size.width / screen->frame_size.width, - (Uint32) current_size.height * new_frame_size.height + (uint32_t) current_size.height * new_frame_size.height / screen->frame_size.height, }; target_size = get_optimal_size(target_size, new_frame_size); @@ -272,11 +273,11 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) { screen->texture = create_texture(screen->renderer, new_frame_size); if (!screen->texture) { LOGC("Could not create texture: %s", SDL_GetError()); - return SDL_FALSE; + return false; } } - return SDL_TRUE; + return true; } // write the frame into the texture @@ -288,20 +289,20 @@ update_texture(struct screen *screen, const AVFrame *frame) { frame->data[2], frame->linesize[2]); } -SDL_bool +bool screen_update_frame(struct screen *screen, struct video_buffer *vb) { mutex_lock(vb->mutex); const AVFrame *frame = video_buffer_consume_rendered_frame(vb); struct size new_frame_size = {frame->width, frame->height}; if (!prepare_for_frame(screen, new_frame_size)) { mutex_unlock(vb->mutex); - return SDL_FALSE; + return false; } update_texture(screen, frame); mutex_unlock(vb->mutex); screen_render(screen); - return SDL_TRUE; + return true; } void @@ -317,7 +318,7 @@ screen_switch_fullscreen(struct screen *screen) { // going to fullscreen, store the current windowed window size screen->windowed_window_size = get_native_window_size(screen->window); } - Uint32 new_mode = screen->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP; + uint32_t new_mode = screen->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP; if (SDL_SetWindowFullscreen(screen->window, new_mode)) { LOGW("Could not switch fullscreen mode: %s", SDL_GetError()); return; diff --git a/app/src/screen.h b/app/src/screen.h index 51f9396d..b3e3ecaa 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -1,6 +1,7 @@ #ifndef SCREEN_H #define SCREEN_H +#include #include #include @@ -15,9 +16,9 @@ struct screen { struct size frame_size; //used only in fullscreen mode to know the windowed window size struct size windowed_window_size; - SDL_bool has_frame; - SDL_bool fullscreen; - SDL_bool no_window; + bool has_frame; + bool fullscreen; + bool no_window; }; #define SCREEN_INITIALIZER { \ @@ -32,13 +33,13 @@ struct screen { .width = 0, \ .height = 0, \ }, \ - .has_frame = SDL_FALSE, \ - .fullscreen = SDL_FALSE, \ - .no_window = SDL_FALSE, \ + .has_frame = false, \ + .fullscreen = false, \ + .no_window = false, \ } // init SDL and set appropriate hints -SDL_bool +bool sdl_init_and_configure(void); // initialize default values @@ -46,9 +47,9 @@ void screen_init(struct screen *screen); // initialize screen, create window, renderer and texture (window is hidden) -SDL_bool +bool screen_init_rendering(struct screen *screen, const char *device_name, - struct size frame_size, SDL_bool always_on_top); + struct size frame_size, bool always_on_top); // show the window void @@ -59,7 +60,7 @@ void screen_destroy(struct screen *screen); // resize if necessary and write the rendered frame into the texture -SDL_bool +bool screen_update_frame(struct screen *screen, struct video_buffer *vb); // render the texture to the renderer diff --git a/app/src/server.c b/app/src/server.c index 1dce347f..6f23d8af 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -30,48 +29,48 @@ get_server_path(void) { return server_path; } -static SDL_bool +static bool push_server(const char *serial) { process_t process = adb_push(serial, get_server_path(), DEVICE_SERVER_PATH); return process_check_success(process, "adb push"); } -static SDL_bool -enable_tunnel_reverse(const char *serial, Uint16 local_port) { +static bool +enable_tunnel_reverse(const char *serial, uint16_t local_port) { process_t process = adb_reverse(serial, SOCKET_NAME, local_port); return process_check_success(process, "adb reverse"); } -static SDL_bool +static bool disable_tunnel_reverse(const char *serial) { process_t process = adb_reverse_remove(serial, SOCKET_NAME); return process_check_success(process, "adb reverse --remove"); } -static SDL_bool -enable_tunnel_forward(const char *serial, Uint16 local_port) { +static bool +enable_tunnel_forward(const char *serial, uint16_t local_port) { process_t process = adb_forward(serial, local_port, SOCKET_NAME); return process_check_success(process, "adb forward"); } -static SDL_bool -disable_tunnel_forward(const char *serial, Uint16 local_port) { +static bool +disable_tunnel_forward(const char *serial, uint16_t local_port) { process_t process = adb_forward_remove(serial, local_port); return process_check_success(process, "adb forward --remove"); } -static SDL_bool +static bool enable_tunnel(struct server *server) { if (enable_tunnel_reverse(server->serial, server->local_port)) { - return SDL_TRUE; + return true; } LOGW("'adb reverse' failed, fallback to 'adb forward'"); - server->tunnel_forward = SDL_TRUE; + server->tunnel_forward = true; return enable_tunnel_forward(server->serial, server->local_port); } -static SDL_bool +static bool disable_tunnel(struct server *server) { if (server->tunnel_forward) { return disable_tunnel_forward(server->serial, server->local_port); @@ -81,9 +80,9 @@ disable_tunnel(struct server *server) { static process_t execute_server(const char *serial, - Uint16 max_size, Uint32 bit_rate, - SDL_bool tunnel_forward, const char *crop, - SDL_bool send_frame_meta) { + uint16_t max_size, uint32_t bit_rate, + bool tunnel_forward, const char *crop, + bool send_frame_meta) { char max_size_string[6]; char bit_rate_string[11]; sprintf(max_size_string, "%"PRIu16, max_size); @@ -106,12 +105,12 @@ execute_server(const char *serial, #define IPV4_LOCALHOST 0x7F000001 static socket_t -listen_on_port(Uint16 port) { +listen_on_port(uint16_t port) { return net_listen(IPV4_LOCALHOST, port, 1); } static socket_t -connect_and_read_byte(Uint16 port) { +connect_and_read_byte(uint16_t port) { socket_t socket = net_connect(IPV4_LOCALHOST, port); if (socket == INVALID_SOCKET) { return INVALID_SOCKET; @@ -128,7 +127,7 @@ connect_and_read_byte(Uint16 port) { } static socket_t -connect_to_server(Uint16 port, Uint32 attempts, Uint32 delay) { +connect_to_server(uint16_t port, uint32_t attempts, uint32_t delay) { do { LOGD("Remaining connection attempts: %d", (int) attempts); socket_t socket = connect_and_read_byte(port); @@ -159,27 +158,27 @@ server_init(struct server *server) { *server = (struct server) SERVER_INITIALIZER; } -SDL_bool +bool server_start(struct server *server, const char *serial, - Uint16 local_port, Uint16 max_size, Uint32 bit_rate, - const char *crop, SDL_bool send_frame_meta) { + uint16_t local_port, uint16_t max_size, uint32_t bit_rate, + const char *crop, bool send_frame_meta) { server->local_port = local_port; if (serial) { server->serial = SDL_strdup(serial); if (!server->serial) { - return SDL_FALSE; + return false; } } if (!push_server(serial)) { SDL_free((void *) server->serial); - return SDL_FALSE; + return false; } if (!enable_tunnel(server)) { SDL_free((void *) server->serial); - return SDL_FALSE; + return false; } // if "adb reverse" does not work (e.g. over "adb connect"), it fallbacks to @@ -197,7 +196,7 @@ server_start(struct server *server, const char *serial, LOGE("Could not listen on port %" PRIu16, local_port); disable_tunnel(server); SDL_free((void *) server->serial); - return SDL_FALSE; + return false; } } @@ -212,12 +211,12 @@ server_start(struct server *server, const char *serial, } disable_tunnel(server); SDL_free((void *) server->serial); - return SDL_FALSE; + return false; } - server->tunnel_enabled = SDL_TRUE; + server->tunnel_enabled = true; - return SDL_TRUE; + return true; } socket_t @@ -225,8 +224,8 @@ server_connect_to(struct server *server) { if (!server->tunnel_forward) { server->device_socket = net_accept(server->server_socket); } else { - Uint32 attempts = 100; - Uint32 delay = 100; // ms + uint32_t attempts = 100; + uint32_t delay = 100; // ms server->device_socket = connect_to_server(server->local_port, attempts, delay); } @@ -242,7 +241,7 @@ server_connect_to(struct server *server) { // we don't need the adb tunnel anymore disable_tunnel(server); // ignore failure - server->tunnel_enabled = SDL_FALSE; + server->tunnel_enabled = false; return server->device_socket; } diff --git a/app/src/server.h b/app/src/server.h index d6d2c3eb..61e0311f 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -1,6 +1,9 @@ #ifndef SERVER_H #define SERVER_H +#include +#include + #include "command.h" #include "net.h" @@ -9,10 +12,10 @@ struct server { process_t process; socket_t server_socket; // only used if !tunnel_forward socket_t device_socket; - Uint16 local_port; - SDL_bool tunnel_enabled; - SDL_bool tunnel_forward; // use "adb forward" instead of "adb reverse" - SDL_bool send_frame_meta; // request frame PTS to be able to record properly + uint16_t local_port; + bool tunnel_enabled; + bool tunnel_forward; // use "adb forward" instead of "adb reverse" + bool send_frame_meta; // request frame PTS to be able to record properly }; #define SERVER_INITIALIZER { \ @@ -21,9 +24,9 @@ struct server { .server_socket = INVALID_SOCKET, \ .device_socket = INVALID_SOCKET, \ .local_port = 0, \ - .tunnel_enabled = SDL_FALSE, \ - .tunnel_forward = SDL_FALSE, \ - .send_frame_meta = SDL_FALSE, \ + .tunnel_enabled = false, \ + .tunnel_forward = false, \ + .send_frame_meta = false, \ } // init default values @@ -31,10 +34,10 @@ void server_init(struct server *server); // push, enable tunnel et start the server -SDL_bool +bool server_start(struct server *server, const char *serial, - Uint16 local_port, Uint16 max_size, Uint32 bit_rate, - const char *crop, SDL_bool send_frame_meta); + uint16_t local_port, uint16_t max_size, uint32_t bit_rate, + const char *crop, bool send_frame_meta); // block until the communication with the server is established socket_t diff --git a/app/src/stream.c b/app/src/stream.c index 2c9ba078..7ed95ee8 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -23,7 +23,7 @@ #define NO_PTS UINT64_C(-1) static struct frame_meta * -frame_meta_new(Uint64 pts) { +frame_meta_new(uint64_t pts) { struct frame_meta *meta = malloc(sizeof(*meta)); if (!meta) { return meta; @@ -38,11 +38,11 @@ frame_meta_delete(struct frame_meta *frame_meta) { free(frame_meta); } -static SDL_bool -receiver_state_push_meta(struct receiver_state *state, Uint64 pts) { +static bool +receiver_state_push_meta(struct receiver_state *state, uint64_t pts) { struct frame_meta *frame_meta = frame_meta_new(pts); if (!frame_meta) { - return SDL_FALSE; + return false; } // append to the list @@ -52,14 +52,14 @@ receiver_state_push_meta(struct receiver_state *state, Uint64 pts) { p = &(*p)->next; } *p = frame_meta; - return SDL_TRUE; + return true; } -static Uint64 +static uint64_t receiver_state_take_meta(struct receiver_state *state) { struct frame_meta *frame_meta = state->frame_meta_queue; // first item SDL_assert(frame_meta); // must not be empty - Uint64 pts = frame_meta->pts; + uint64_t pts = frame_meta->pts; state->frame_meta_queue = frame_meta->next; // remove the item frame_meta_delete(frame_meta); return pts; @@ -95,7 +95,7 @@ read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { // no partial read (net_recv_all()) SDL_assert_release(r == HEADER_SIZE); - Uint64 pts = buffer_read64be(header); + uint64_t pts = buffer_read64be(header); state->remaining = buffer_read32be(&header[8]); if (pts != NO_PTS && !receiver_state_push_meta(state, pts)) { @@ -215,7 +215,7 @@ run_stream(void *data) { if (stream->recorder) { // we retrieve the PTS in order they were received, so they will // be assigned to the correct frame - Uint64 pts = receiver_state_take_meta(&stream->receiver_state); + uint64_t pts = receiver_state_take_meta(&stream->receiver_state); packet.pts = pts; packet.dts = pts; @@ -261,16 +261,16 @@ stream_init(struct stream *stream, socket_t socket, stream->recorder = recorder; } -SDL_bool +bool stream_start(struct stream *stream) { LOGD("Starting stream thread"); stream->thread = SDL_CreateThread(run_stream, "stream", stream); if (!stream->thread) { LOGC("Could not start stream thread"); - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } void diff --git a/app/src/stream.h b/app/src/stream.h index d8b61857..d5eda0ac 100644 --- a/app/src/stream.h +++ b/app/src/stream.h @@ -1,7 +1,8 @@ #ifndef STREAM_H #define STREAM_H -#include +#include +#include #include #include "net.h" @@ -9,7 +10,7 @@ struct video_buffer; struct frame_meta { - Uint64 pts; + uint64_t pts; struct frame_meta *next; }; @@ -30,7 +31,7 @@ void stream_init(struct stream *stream, socket_t socket, struct decoder *decoder, struct recorder *recorder); -SDL_bool +bool stream_start(struct stream *stream); void diff --git a/app/src/sys/unix/command.c b/app/src/sys/unix/command.c index cec215aa..fa41571e 100644 --- a/app/src/sys/unix/command.c +++ b/app/src/sys/unix/command.c @@ -73,7 +73,7 @@ end: return ret; } -SDL_bool +bool cmd_terminate(pid_t pid) { if (pid <= 0) { LOGC("Requested to kill %d, this is an error. Please report the bug.\n", @@ -83,7 +83,7 @@ cmd_terminate(pid_t pid) { return kill(pid, SIGTERM) != -1; } -SDL_bool +bool cmd_simple_wait(pid_t pid, int *exit_code) { int status; int code; diff --git a/app/src/sys/unix/net.c b/app/src/sys/unix/net.c index 7fed5ebb..199cd7c2 100644 --- a/app/src/sys/unix/net.c +++ b/app/src/sys/unix/net.c @@ -1,11 +1,11 @@ #include "net.h" -# include +#include -SDL_bool +bool net_init(void) { // do nothing - return SDL_TRUE; + return true; } void @@ -13,7 +13,7 @@ net_cleanup(void) { // do nothing } -SDL_bool +bool net_close(socket_t socket) { return !close(socket); } diff --git a/app/src/sys/win/command.c b/app/src/sys/win/command.c index c5580946..1cd7274f 100644 --- a/app/src/sys/win/command.c +++ b/app/src/sys/win/command.c @@ -57,12 +57,12 @@ cmd_execute(const char *path, const char *const argv[], HANDLE *handle) { return PROCESS_SUCCESS; } -SDL_bool +bool cmd_terminate(HANDLE handle) { return TerminateProcess(handle, 1) && CloseHandle(handle); } -SDL_bool +bool cmd_simple_wait(HANDLE handle, DWORD *exit_code) { DWORD code; if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 diff --git a/app/src/sys/win/net.c b/app/src/sys/win/net.c index 0ca55f9b..dc483682 100644 --- a/app/src/sys/win/net.c +++ b/app/src/sys/win/net.c @@ -2,15 +2,15 @@ #include "log.h" -SDL_bool +bool net_init(void) { WSADATA wsa; int res = WSAStartup(MAKEWORD(2, 2), &wsa) < 0; if (res < 0) { LOGC("WSAStartup failed with error %d", res); - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } void @@ -18,7 +18,7 @@ net_cleanup(void) { WSACleanup(); } -SDL_bool +bool net_close(socket_t socket) { return !closesocket(socket); } diff --git a/app/src/tiny_xpm.c b/app/src/tiny_xpm.c index b9efd575..01fd280f 100644 --- a/app/src/tiny_xpm.c +++ b/app/src/tiny_xpm.c @@ -1,5 +1,7 @@ #include "tiny_xpm.h" +#include +#include #include #include @@ -7,20 +9,20 @@ struct index { char c; - Uint32 color; + uint32_t color; }; -static SDL_bool -find_color(struct index *index, int len, char c, Uint32 *color) { +static bool +find_color(struct index *index, int len, char c, uint32_t *color) { // there are typically very few color, so it's ok to iterate over the array for (int i = 0; i < len; ++i) { if (index[i].c == c) { *color = index[i].color; - return SDL_TRUE; + return true; } } *color = 0; - return SDL_FALSE; + return false; } // We encounter some problems with SDL2_image on MSYS2 (Windows), @@ -71,7 +73,7 @@ read_xpm(char *xpm[]) { } // parse image - Uint32 *pixels = SDL_malloc(4 * width * height); + uint32_t *pixels = SDL_malloc(4 * width * height); if (!pixels) { LOGE("Could not allocate icon memory"); return NULL; @@ -80,23 +82,23 @@ read_xpm(char *xpm[]) { const char *line = xpm[1 + colors + y]; for (int x = 0; x < width; ++x) { char c = line[x]; - Uint32 color; - SDL_bool color_found = find_color(index, colors, c, &color); + uint32_t color; + bool color_found = find_color(index, colors, c, &color); SDL_assert(color_found); pixels[y * width + x] = color; } } #if SDL_BYTEORDER == SDL_BIG_ENDIAN - Uint32 amask = 0x000000ff; - Uint32 rmask = 0x0000ff00; - Uint32 gmask = 0x00ff0000; - Uint32 bmask = 0xff000000; + uint32_t amask = 0x000000ff; + uint32_t rmask = 0x0000ff00; + uint32_t gmask = 0x00ff0000; + uint32_t bmask = 0xff000000; #else // little endian, like x86 - Uint32 amask = 0xff000000; - Uint32 rmask = 0x00ff0000; - Uint32 gmask = 0x0000ff00; - Uint32 bmask = 0x000000ff; + uint32_t amask = 0xff000000; + uint32_t rmask = 0x00ff0000; + uint32_t gmask = 0x0000ff00; + uint32_t bmask = 0x000000ff; #endif SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(pixels, diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index f7c34bef..b56ae9f2 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -9,7 +9,7 @@ #include "lock_util.h" #include "log.h" -SDL_bool +bool video_buffer_init(struct video_buffer *vb) { if (!(vb->decoding_frame = av_frame_alloc())) { goto error_0; @@ -28,22 +28,22 @@ video_buffer_init(struct video_buffer *vb) { SDL_DestroyMutex(vb->mutex); goto error_2; } - vb->interrupted = SDL_FALSE; + vb->interrupted = false; #endif // there is initially no rendering frame, so consider it has already been // consumed - vb->rendering_frame_consumed = SDL_TRUE; + vb->rendering_frame_consumed = true; fps_counter_init(&vb->fps_counter); - return SDL_TRUE; + return true; error_2: av_frame_free(&vb->rendering_frame); error_1: av_frame_free(&vb->decoding_frame); error_0: - return SDL_FALSE; + return false; } void @@ -63,7 +63,7 @@ video_buffer_swap_frames(struct video_buffer *vb) { vb->rendering_frame = tmp; } -SDL_bool +bool video_buffer_offer_decoded_frame(struct video_buffer *vb) { mutex_lock(vb->mutex); #ifndef SKIP_FRAMES @@ -80,8 +80,8 @@ video_buffer_offer_decoded_frame(struct video_buffer *vb) { video_buffer_swap_frames(vb); - SDL_bool previous_frame_consumed = vb->rendering_frame_consumed; - vb->rendering_frame_consumed = SDL_FALSE; + bool previous_frame_consumed = vb->rendering_frame_consumed; + vb->rendering_frame_consumed = false; mutex_unlock(vb->mutex); return previous_frame_consumed; @@ -90,7 +90,7 @@ video_buffer_offer_decoded_frame(struct video_buffer *vb) { const AVFrame * video_buffer_consume_rendered_frame(struct video_buffer *vb) { SDL_assert(!vb->rendering_frame_consumed); - vb->rendering_frame_consumed = SDL_TRUE; + vb->rendering_frame_consumed = true; if (vb->fps_counter.started) { fps_counter_add_rendered_frame(&vb->fps_counter); } @@ -108,7 +108,7 @@ video_buffer_interrupt(struct video_buffer *vb) { (void) vb; // unused #else mutex_lock(vb->mutex); - vb->interrupted = SDL_TRUE; + vb->interrupted = true; mutex_unlock(vb->mutex); // wake up blocking wait cond_signal(vb->rendering_frame_consumed_cond); diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index e9a72f50..03bcaa18 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -1,8 +1,8 @@ #ifndef VIDEO_BUFFER_H #define VIDEO_BUFFER_H +#include #include -#include #include "config.h" #include "fps_counter.h" @@ -15,14 +15,14 @@ struct video_buffer { AVFrame *rendering_frame; SDL_mutex *mutex; #ifndef SKIP_FRAMES - SDL_bool interrupted; + bool interrupted; SDL_cond *rendering_frame_consumed_cond; #endif - SDL_bool rendering_frame_consumed; + bool rendering_frame_consumed; struct fps_counter fps_counter; }; -SDL_bool +bool video_buffer_init(struct video_buffer *vb); void @@ -31,7 +31,7 @@ video_buffer_destroy(struct video_buffer *vb); // set the decoded frame as ready for rendering // this function locks frames->mutex during its execution // returns true if the previous frame had been consumed -SDL_bool +bool video_buffer_offer_decoded_frame(struct video_buffer *vb); // mark the rendering frame as consumed and return it From 9ef345fdd0eff7b779cea8bb6e8c3acd65e084a9 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 3 Mar 2019 00:01:16 +0100 Subject: [PATCH 20/24] Make owned serial a pointer-to-non-const The server owns the serial, so it needs to free it. Therefore, it should not be a pointer-to-const. --- app/src/server.c | 8 ++++---- app/src/server.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/server.c b/app/src/server.c index 6f23d8af..972fbbaa 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -172,12 +172,12 @@ server_start(struct server *server, const char *serial, } if (!push_server(serial)) { - SDL_free((void *) server->serial); + SDL_free(server->serial); return false; } if (!enable_tunnel(server)) { - SDL_free((void *) server->serial); + SDL_free(server->serial); return false; } @@ -195,7 +195,7 @@ server_start(struct server *server, const char *serial, if (server->server_socket == INVALID_SOCKET) { LOGE("Could not listen on port %" PRIu16, local_port); disable_tunnel(server); - SDL_free((void *) server->serial); + SDL_free(server->serial); return false; } } @@ -271,5 +271,5 @@ server_destroy(struct server *server) { if (server->device_socket != INVALID_SOCKET) { close_socket(&server->device_socket); } - SDL_free((void *) server->serial); + SDL_free(server->serial); } diff --git a/app/src/server.h b/app/src/server.h index 61e0311f..0f25d48f 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -8,7 +8,7 @@ #include "net.h" struct server { - const char *serial; + char *serial; process_t process; socket_t server_socket; // only used if !tunnel_forward socket_t device_socket; From 8595862005ebfb8a02081bea593884b308c19b49 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 3 Mar 2019 00:26:48 +0100 Subject: [PATCH 21/24] Use explicit output parameter for skipped frame The function video_buffer_offer_decoded_frame() returned a bool to indicate whether the previous frame had been consumed. This was confusing, because we could expect the returned bool report whether the action succeeded. Make the semantic explicit by using an output parameter. Also revert the flag (report if the frame has been skipped instead of consumed) to avoid confusion for the first frame (the previous is neither skipped nor consumed because there is no previous frame). --- app/src/decoder.c | 7 ++++--- app/src/video_buffer.c | 8 ++++---- app/src/video_buffer.h | 7 ++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index 59bd94ce..b206ebe0 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -20,9 +20,10 @@ // set the decoded frame as ready for rendering, and notify static void push_frame(struct decoder *decoder) { - bool previous_frame_consumed = - video_buffer_offer_decoded_frame(decoder->video_buffer); - if (!previous_frame_consumed) { + bool previous_frame_skipped; + video_buffer_offer_decoded_frame(decoder->video_buffer, + &previous_frame_skipped); + if (previous_frame_skipped) { // the previous EVENT_NEW_FRAME will consume this frame return; } diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index b56ae9f2..8f1d1d9d 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -63,8 +63,9 @@ video_buffer_swap_frames(struct video_buffer *vb) { vb->rendering_frame = tmp; } -bool -video_buffer_offer_decoded_frame(struct video_buffer *vb) { +void +video_buffer_offer_decoded_frame(struct video_buffer *vb, + bool *previous_frame_skipped) { mutex_lock(vb->mutex); #ifndef SKIP_FRAMES // if SKIP_FRAMES is disabled, then the decoder must wait for the current @@ -80,11 +81,10 @@ video_buffer_offer_decoded_frame(struct video_buffer *vb) { video_buffer_swap_frames(vb); - bool previous_frame_consumed = vb->rendering_frame_consumed; + *previous_frame_skipped = !vb->rendering_frame_consumed; vb->rendering_frame_consumed = false; mutex_unlock(vb->mutex); - return previous_frame_consumed; } const AVFrame * diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index 03bcaa18..93222236 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -30,9 +30,10 @@ video_buffer_destroy(struct video_buffer *vb); // set the decoded frame as ready for rendering // this function locks frames->mutex during its execution -// returns true if the previous frame had been consumed -bool -video_buffer_offer_decoded_frame(struct video_buffer *vb); +// the output flag is set to report whether the previous frame has been skipped +void +video_buffer_offer_decoded_frame(struct video_buffer *vb, + bool *previous_frame_skipped); // mark the rendering frame as consumed and return it // MUST be called with frames->mutex locked!!! From 6baed8a06fc05a9bc2e6d7aeef2b17c3cc5da98f Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 3 Mar 2019 01:40:03 +0100 Subject: [PATCH 22/24] Do not init SDL video subsystem if no display The SDL video subsystem is not necessary if we don't display the video. Move the sdl_init_and_configure() function from screen.c to scrcpy.c, because it is not only related to the screen display. --- app/src/scrcpy.c | 42 ++++++++++++++++++++++++++++++++++++++---- app/src/screen.c | 27 --------------------------- app/src/screen.h | 4 ---- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 26bde219..c2428c61 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -42,6 +42,40 @@ static struct input_manager input_manager = { .control = true, }; +// init SDL and set appropriate hints +static bool +sdl_init_and_configure(bool display) { + uint32_t flags = display ? SDL_INIT_VIDEO : SDL_INIT_EVENTS; + if (SDL_Init(flags)) { + LOGC("Could not initialize SDL: %s", SDL_GetError()); + return false; + } + + atexit(SDL_Quit); + + if (!display) { + return true; + } + + // Use the best available scale quality + if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2")) { + LOGW("Could not enable bilinear filtering"); + } + +#ifdef SCRCPY_SDL_HAS_HINT_MOUSE_FOCUS_CLICKTHROUGH + // Handle a click to gain focus as any other click + if (!SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")) { + LOGW("Could not enable mouse focus clickthrough"); + } +#endif + + // Do not disable the screensaver when scrcpy is running + SDL_EnableScreenSaver(); + + return true; +} + + #if defined(__APPLE__) || defined(__WINDOWS__) # define CONTINUOUS_RESIZING_WORKAROUND #endif @@ -240,7 +274,10 @@ scrcpy(const struct scrcpy_options *options) { bool ret = true; - if (!sdl_init_and_configure()) { + bool display = !options->no_display; + bool control = !options->no_control; + + if (!sdl_init_and_configure(display)) { ret = false; goto finally_destroy_server; } @@ -264,9 +301,6 @@ scrcpy(const struct scrcpy_options *options) { goto finally_destroy_server; } - bool display = !options->no_display; - bool control = !options->no_control; - input_manager.control = control; struct decoder *dec = NULL; diff --git a/app/src/screen.c b/app/src/screen.c index 962d5b70..f6e917a9 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -13,33 +13,6 @@ #define DISPLAY_MARGINS 96 -bool -sdl_init_and_configure(void) { - if (SDL_Init(SDL_INIT_VIDEO)) { - LOGC("Could not initialize SDL: %s", SDL_GetError()); - return false; - } - - atexit(SDL_Quit); - - // Use the best available scale quality - if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2")) { - LOGW("Could not enable bilinear filtering"); - } - -#ifdef SCRCPY_SDL_HAS_HINT_MOUSE_FOCUS_CLICKTHROUGH - // Handle a click to gain focus as any other click - if (!SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")) { - LOGW("Could not enable mouse focus clickthrough"); - } -#endif - - // Do not disable the screensaver when scrcpy is running - SDL_EnableScreenSaver(); - - return true; -} - // get the window size in a struct size static struct size get_native_window_size(SDL_Window *window) { diff --git a/app/src/screen.h b/app/src/screen.h index b3e3ecaa..5734fdc2 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -38,10 +38,6 @@ struct screen { .no_window = false, \ } -// init SDL and set appropriate hints -bool -sdl_init_and_configure(void); - // initialize default values void screen_init(struct screen *screen); From f7efafd846e0d5597c6b198f523f1517bf8af782 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 3 Mar 2019 11:05:26 +0100 Subject: [PATCH 23/24] Explicitly pass control flag to input manager Replace the "global" control flag in the input_manager by a function parameter to make explicit that the behavior depends whether --no-control has been set. --- app/src/input_manager.c | 12 ++++-------- app/src/input_manager.h | 7 ++++--- app/src/scrcpy.c | 8 +++----- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/app/src/input_manager.c b/app/src/input_manager.c index eb4047e9..f77d2d26 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -191,7 +191,8 @@ input_manager_process_text_input(struct input_manager *input_manager, void input_manager_process_key(struct input_manager *input_manager, - const SDL_KeyboardEvent *event) { + const SDL_KeyboardEvent *event, + bool control) { bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL); bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT); bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI); @@ -202,9 +203,6 @@ input_manager_process_key(struct input_manager *input_manager, return; } - // false if the user requested not to interact with the device - bool control = input_manager->control; - // capture all Ctrl events if (ctrl | meta) { SDL_Keycode keycode = event->keysym.sym; @@ -341,10 +339,8 @@ is_outside_device_screen(struct input_manager *input_manager, int x, int y) void input_manager_process_mouse_button(struct input_manager *input_manager, - const SDL_MouseButtonEvent *event) { - // false if the user requested not to interact with the device - bool control = input_manager->control; - + const SDL_MouseButtonEvent *event, + bool control) { if (event->type == SDL_MOUSEBUTTONDOWN) { if (control && event->button == SDL_BUTTON_RIGHT) { press_back_or_turn_screen_on(input_manager->controller); diff --git a/app/src/input_manager.h b/app/src/input_manager.h index c30a8188..83cb7405 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -13,7 +13,6 @@ struct input_manager { struct controller *controller; struct video_buffer *video_buffer; struct screen *screen; - bool control; }; void @@ -22,7 +21,8 @@ input_manager_process_text_input(struct input_manager *input_manager, void input_manager_process_key(struct input_manager *input_manager, - const SDL_KeyboardEvent *event); + const SDL_KeyboardEvent *event, + bool control); void input_manager_process_mouse_motion(struct input_manager *input_manager, @@ -30,7 +30,8 @@ input_manager_process_mouse_motion(struct input_manager *input_manager, void input_manager_process_mouse_button(struct input_manager *input_manager, - const SDL_MouseButtonEvent *event); + const SDL_MouseButtonEvent *event, + bool control); void input_manager_process_mouse_wheel(struct input_manager *input_manager, diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index c2428c61..61b3f8d9 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -39,7 +39,6 @@ static struct input_manager input_manager = { .controller = &controller, .video_buffer = &video_buffer, .screen = &screen, - .control = true, }; // init SDL and set appropriate hints @@ -146,7 +145,7 @@ handle_event(SDL_Event *event, bool control) { 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); + input_manager_process_key(&input_manager, &event->key, control); break; case SDL_MOUSEMOTION: if (!control) { @@ -164,7 +163,8 @@ handle_event(SDL_Event *event, bool control) { 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); + input_manager_process_mouse_button(&input_manager, &event->button, + control); break; case SDL_DROPFILE: { if (!control) { @@ -301,8 +301,6 @@ scrcpy(const struct scrcpy_options *options) { goto finally_destroy_server; } - input_manager.control = control; - struct decoder *dec = NULL; if (display) { if (!video_buffer_init(&video_buffer)) { From a7b3901c3174975e818e3ef345fadfa10d4b6f25 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 3 Mar 2019 11:59:31 +0100 Subject: [PATCH 24/24] Add more consts Some decoder and recorder functions must not write to AVCodec and AVPacket. --- app/src/decoder.c | 4 ++-- app/src/decoder.h | 4 ++-- app/src/recorder.c | 4 ++-- app/src/recorder.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index b206ebe0..8fa218f4 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -39,7 +39,7 @@ decoder_init(struct decoder *decoder, struct video_buffer *vb) { } bool -decoder_open(struct decoder *decoder, AVCodec *codec) { +decoder_open(struct decoder *decoder, const AVCodec *codec) { decoder->codec_ctx = avcodec_alloc_context3(codec); if (!decoder->codec_ctx) { LOGC("Could not allocate decoder context"); @@ -62,7 +62,7 @@ decoder_close(struct decoder *decoder) { } bool -decoder_push(struct decoder *decoder, AVPacket *packet) { +decoder_push(struct decoder *decoder, const AVPacket *packet) { // the new decoding/encoding API has been introduced by: // #ifdef SCRCPY_LAVF_HAS_NEW_ENCODING_DECODING_API diff --git a/app/src/decoder.h b/app/src/decoder.h index c6349281..76fee80e 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -15,13 +15,13 @@ void decoder_init(struct decoder *decoder, struct video_buffer *vb); bool -decoder_open(struct decoder *decoder, AVCodec *codec); +decoder_open(struct decoder *decoder, const AVCodec *codec); void decoder_close(struct decoder *decoder); bool -decoder_push(struct decoder *decoder, AVPacket *packet); +decoder_push(struct decoder *decoder, const AVPacket *packet); void decoder_interrupt(struct decoder *decoder); diff --git a/app/src/recorder.c b/app/src/recorder.c index 2f33702d..321a17ee 100644 --- a/app/src/recorder.c +++ b/app/src/recorder.c @@ -59,7 +59,7 @@ recorder_get_format_name(enum recorder_format format) { } bool -recorder_open(struct recorder *recorder, AVCodec *input_codec) { +recorder_open(struct recorder *recorder, const AVCodec *input_codec) { const char *format_name = recorder_get_format_name(recorder->format); SDL_assert(format_name); const AVOutputFormat *format = find_muxer(format_name); @@ -128,7 +128,7 @@ recorder_close(struct recorder *recorder) { } static bool -recorder_write_header(struct recorder *recorder, AVPacket *packet) { +recorder_write_header(struct recorder *recorder, const AVPacket *packet) { AVStream *ostream = recorder->ctx->streams[0]; uint8_t *extradata = av_malloc(packet->size * sizeof(uint8_t)); diff --git a/app/src/recorder.h b/app/src/recorder.h index c126b29b..26c4a3c3 100644 --- a/app/src/recorder.h +++ b/app/src/recorder.h @@ -27,7 +27,7 @@ void recorder_destroy(struct recorder *recorder); bool -recorder_open(struct recorder *recorder, AVCodec *input_codec); +recorder_open(struct recorder *recorder, const AVCodec *input_codec); void recorder_close(struct recorder *recorder);