scrcpy.c 5.5 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;
    }

R
Romain Vimont 已提交
114 115 116
    // to reduce startup time, we could be tempted to init other stuff before blocking here
    // but we should not block after SDL_Init since it handles the signals (Ctrl+C) in its
    // event loop: blocking could lead to deadlock
117
    TCPsocket device_socket = server_connect_to(&server, serial);
R
Romain Vimont 已提交
118
    if (!device_socket) {
119
        server_stop(&server, serial);
120 121
        ret = SDL_FALSE;
        goto finally_destroy_server;
R
Romain Vimont 已提交
122 123 124
    }

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

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

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

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

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

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

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

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

    event_loop();

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

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