scrcpy.c 5.6 KB
Newer Older
R
Romain Vimont 已提交
1
#include "scrcpy.h"
R
Romain Vimont 已提交
2

R
Romain Vimont 已提交
3 4
#include <stdio.h>
#include <string.h>
R
Romain Vimont 已提交
5 6
#include <unistd.h>
#include <libavformat/avformat.h>
R
Romain Vimont 已提交
7
#include <sys/time.h>
R
Romain Vimont 已提交
8
#include <SDL2/SDL.h>
R
Romain Vimont 已提交
9
#include <SDL2/SDL_net.h>
R
Romain Vimont 已提交
10

R
Romain Vimont 已提交
11 12
#include "command.h"
#include "common.h"
R
Romain Vimont 已提交
13
#include "controller.h"
R
Romain Vimont 已提交
14
#include "decoder.h"
15
#include "device.h"
R
Romain Vimont 已提交
16 17 18 19
#include "events.h"
#include "frames.h"
#include "lockutil.h"
#include "netutil.h"
20
#include "screen.h"
21
#include "screencontrol.h"
R
Romain Vimont 已提交
22
#include "server.h"
R
Romain Vimont 已提交
23
#include "tinyxpm.h"
R
Romain Vimont 已提交
24

25
static struct server server = SERVER_INITIALIZER;
26
static struct screen screen = SCREEN_INITIALIZER;
R
Romain Vimont 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
static struct frames frames;
static struct decoder decoder;
static struct controller controller;

static long timestamp_ms(void) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

static void count_frame(void) {
    static long ts = 0;
    static int nbframes = 0;
    long now = timestamp_ms();
    ++nbframes;
    if (now - ts > 1000) {
        SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "%d fps", nbframes);
        ts = now;
        nbframes = 0;
    }
}

R
Romain Vimont 已提交
49
static void event_loop(void) {
R
Romain Vimont 已提交
50 51 52
    SDL_Event event;
    while (SDL_WaitEvent(&event)) {
        switch (event.type) {
R
Romain Vimont 已提交
53 54
            case EVENT_DECODER_STOPPED:
                SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Video decoder stopped");
R
Romain Vimont 已提交
55
                return;
R
Romain Vimont 已提交
56
            case SDL_QUIT:
R
Romain Vimont 已提交
57
                SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "User requested to quit");
R
Romain Vimont 已提交
58
                return;
R
Romain Vimont 已提交
59
            case EVENT_NEW_FRAME:
R
Romain Vimont 已提交
60 61 62 63 64
                if (!screen.has_frame) {
                    screen.has_frame = SDL_TRUE;
                    // this is the very first frame, show the window
                    screen_show_window(&screen);
                }
R
Romain Vimont 已提交
65
                if (!screen_update_frame(&screen, &frames)) {
R
Romain Vimont 已提交
66 67 68 69 70 71 72 73
                    return;
                }
                count_frame(); // display fps for debug
                break;
            case SDL_WINDOWEVENT:
                switch (event.window.event) {
                case SDL_WINDOWEVENT_EXPOSED:
                case SDL_WINDOWEVENT_SIZE_CHANGED:
74
                    screen_render(&screen);
R
Romain Vimont 已提交
75 76 77 78
                    break;
                }
                break;
            case SDL_TEXTINPUT: {
79
                screencontrol_handle_text_input(&controller, &screen, &event.text);
R
Romain Vimont 已提交
80
                break;
R
Romain Vimont 已提交
81
            }
R
Romain Vimont 已提交
82 83
            case SDL_KEYDOWN:
            case SDL_KEYUP:
84
                screencontrol_handle_key(&controller, &screen, &event.key);
R
Romain Vimont 已提交
85 86
                break;
            case SDL_MOUSEMOTION:
87
                screencontrol_handle_mouse_motion(&controller, &screen, &event.motion);
R
Romain Vimont 已提交
88 89
                break;
            case SDL_MOUSEWHEEL: {
90
                screencontrol_handle_mouse_wheel(&controller, &screen, &event.wheel);
R
Romain Vimont 已提交
91 92 93 94
                break;
            }
            case SDL_MOUSEBUTTONDOWN:
            case SDL_MOUSEBUTTONUP: {
95
                screencontrol_handle_mouse_button(&controller, &screen, &event.button);
R
Romain Vimont 已提交
96 97 98 99 100 101
                break;
            }
        }
    }
}

R
Romain Vimont 已提交
102
SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 bit_rate) {
103
    if (!server_start(&server, serial, local_port, max_size, bit_rate)) {
R
Romain Vimont 已提交
104 105 106
        return SDL_FALSE;
    }

107 108
    SDL_bool ret = SDL_TRUE;

R
Romain Vimont 已提交
109 110 111 112 113
    if (!sdl_init_and_configure()) {
        ret = SDL_FALSE;
        goto finally_destroy_server;
    }

114 115 116 117 118
    // SDL initialization replace the signal handler for SIGTERM, so Ctrl+C is
    // managed by the event loop. This blocking call blocks the event loop, so
    // timeout the connection not to block indefinitely in case of SIGTERM.
#define SERVER_CONNECT_TIMEOUT_MS 2000
    TCPsocket device_socket = server_connect_to(&server, serial, SERVER_CONNECT_TIMEOUT_MS);
R
Romain Vimont 已提交
119
    if (!device_socket) {
120
        server_stop(&server, serial);
121 122
        ret = SDL_FALSE;
        goto finally_destroy_server;
R
Romain Vimont 已提交
123 124 125
    }

    char device_name[DEVICE_NAME_FIELD_LENGTH];
126
    struct size frame_size;
R
Romain Vimont 已提交
127 128 129 130

    // 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
131
    if (!device_read_info(device_socket, device_name, &frame_size)) {
132
        server_stop(&server, serial);
133 134
        ret = SDL_FALSE;
        goto finally_destroy_server;
R
Romain Vimont 已提交
135 136 137
    }

    if (!frames_init(&frames)) {
138
        server_stop(&server, serial);
139 140
        ret = SDL_FALSE;
        goto finally_destroy_server;
R
Romain Vimont 已提交
141 142
    }

R
Romain Vimont 已提交
143
    decoder_init(&decoder, &frames, device_socket);
R
Romain Vimont 已提交
144 145 146 147 148

    // now we consumed the header values, the socket receives the video stream
    // start the decoder
    if (!decoder_start(&decoder)) {
        ret = SDL_FALSE;
149
        server_stop(&server, serial);
150
        goto finally_destroy_frames;
R
Romain Vimont 已提交
151 152 153 154
    }

    if (!controller_init(&controller, device_socket)) {
        ret = SDL_FALSE;
155
        goto finally_stop_decoder;
R
Romain Vimont 已提交
156 157 158 159
    }

    if (!controller_start(&controller)) {
        ret = SDL_FALSE;
160
        goto finally_destroy_controller;
R
Romain Vimont 已提交
161 162
    }

163
    if (!screen_init_rendering(&screen, device_name, frame_size)) {
R
Romain Vimont 已提交
164
        ret = SDL_FALSE;
165
        goto finally_stop_and_join_controller;
R
Romain Vimont 已提交
166
    }
R
Romain Vimont 已提交
167 168 169 170

    event_loop();

    SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "quit...");
171 172
    screen_destroy(&screen);
finally_stop_and_join_controller:
R
Romain Vimont 已提交
173 174
    controller_stop(&controller);
    controller_join(&controller);
175
finally_destroy_controller:
R
Romain Vimont 已提交
176
    controller_destroy(&controller);
177
finally_stop_decoder:
178
    decoder_stop(&decoder);
R
Romain Vimont 已提交
179
    // kill the server before decoder_join() to wake up the decoder
180
    server_stop(&server, serial);
R
Romain Vimont 已提交
181
    decoder_join(&decoder);
182
finally_destroy_frames:
R
Romain Vimont 已提交
183
    frames_destroy(&frames);
184 185
finally_destroy_server:
    server_destroy(&server);
R
Romain Vimont 已提交
186

R
Romain Vimont 已提交
187
    return ret;
R
Romain Vimont 已提交
188
}