Compare commits

..

1 Commits

Author SHA1 Message Date
d113b6ef61 buffered_reader
Not merged: it has not visible impact on CPU usage.
2019-07-31 15:56:31 +02:00
15 changed files with 261 additions and 219 deletions

View File

@ -125,12 +125,12 @@ dist-win64: build-server build-win64 build-win64-noconsole
cp prebuilt-deps/SDL2-2.0.8/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/SDL2-2.0.8/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
zip-win32: dist-win32 zip-win32: dist-win32
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \ cd "$(DIST)"; \
zip -r "../$(WIN32_TARGET)" . zip -r "$(WIN32_TARGET)" "$(WIN32_TARGET_DIR)"
zip-win64: dist-win64 zip-win64: dist-win64
cd "$(DIST)/$(WIN64_TARGET_DIR)"; \ cd "$(DIST)"; \
zip -r "../$(WIN64_TARGET)" . zip -r "$(WIN64_TARGET)" "$(WIN64_TARGET_DIR)"
sums: sums:
cd "$(DIST)"; \ cd "$(DIST)"; \

View File

@ -315,26 +315,26 @@ Also see [issue #14].
## Shortcuts ## Shortcuts
| Action | Shortcut | Shortcut (macOS) | Action | Shortcut |
| -------------------------------------- |:----------------------------- |:----------------------------- | -------------------------------------- |:---------------------------- |
| Switch fullscreen mode | `Ctrl`+`f` | `Cmd`+`f` | Switch fullscreen mode | `Ctrl`+`f` |
| Resize window to 1:1 (pixel-perfect) | `Ctrl`+`g` | `Cmd`+`g` | Resize window to 1:1 (pixel-perfect) | `Ctrl`+`g` |
| Resize window to remove black borders | `Ctrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_ | Resize window to remove black borders | `Ctrl`+`x` \| _Double-click¹_ |
| Click on `HOME` | `Ctrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_ | Click on `HOME` | `Ctrl`+`h` \| _Middle-click_ |
| Click on `BACK` | `Ctrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_ | Click on `BACK` | `Ctrl`+`b` \| _Right-click²_ |
| Click on `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s` | Click on `APP_SWITCH` | `Ctrl`+`s` |
| Click on `MENU` | `Ctrl`+`m` | `Ctrl`+`m` | Click on `MENU` | `Ctrl`+`m` |
| Click on `VOLUME_UP` | `Ctrl`+`↑` _(up)_ | `Cmd`+`↑` _(up)_ | Click on `VOLUME_UP` | `Ctrl`+`↑` _(up)_ (`Cmd`+`↑` on macOS) |
| Click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ | `Cmd`+`↓` _(down)_ | Click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ (`Cmd`+`↓` on macOS) |
| Click on `POWER` | `Ctrl`+`p` | `Cmd`+`p` | Click on `POWER` | `Ctrl`+`p` |
| Power on | _Right-click²_ | _Right-click²_ | Power on | _Right-click²_ |
| Turn device screen off (keep mirroring)| `Ctrl`+`o` | `Cmd`+`o` | Turn device screen off (keep mirroring)| `Ctrl`+`o` |
| Expand notification panel | `Ctrl`+`n` | `Cmd`+`n` | Expand notification panel | `Ctrl`+`n` |
| Collapse notification panel | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n` | Collapse notification panel | `Ctrl`+`Shift`+`n` |
| Copy device clipboard to computer | `Ctrl`+`c` | `Cmd`+`c` | Copy device clipboard to computer | `Ctrl`+`c` |
| Paste computer clipboard to device | `Ctrl`+`v` | `Cmd`+`v` | Paste computer clipboard to device | `Ctrl`+`v` |
| Copy computer clipboard to device | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v` | Copy computer clipboard to device | `Ctrl`+`Shift`+`v` |
| Enable/disable FPS counter (on stdout) | `Ctrl`+`i` | `Cmd`+`i` | Enable/disable FPS counter (on stdout) | `Ctrl`+`i` |
_¹Double-click on black borders to remove them._ _¹Double-click on black borders to remove them._
_²Right-click turns the screen on if it was off, presses BACK otherwise._ _²Right-click turns the screen on if it was off, presses BACK otherwise._

View File

@ -1,5 +1,6 @@
src = [ src = [
'src/main.c', 'src/main.c',
'src/buffered_reader.c',
'src/command.c', 'src/command.c',
'src/control_msg.c', 'src/control_msg.c',
'src/controller.c', 'src/controller.c',
@ -150,9 +151,6 @@ tests = [
'tests/test_device_msg_deserialize.c', 'tests/test_device_msg_deserialize.c',
'src/device_msg.c' 'src/device_msg.c'
]], ]],
['test_queue', [
'tests/test_queue.c',
]],
['test_strutil', [ ['test_strutil', [
'tests/test_strutil.c', 'tests/test_strutil.c',
'src/str_util.c' 'src/str_util.c'

72
app/src/buffered_reader.c Normal file
View File

@ -0,0 +1,72 @@
#include "buffered_reader.h"
#include <SDL2/SDL_assert.h>
#include "log.h"
bool
buffered_reader_init(struct buffered_reader *reader, socket_t socket,
size_t bufsize) {
reader->buf = SDL_malloc(bufsize);
if (!reader->buf) {
LOGC("Could not allocate buffer");
return false;
}
reader->socket = socket;
reader->bufsize = bufsize;
reader->offset = 0;
reader->len = 0;
return true;
}
void
buffered_reader_destroy(struct buffered_reader *reader) {
SDL_free(reader->buf);
}
static ssize_t
buffered_reader_fill(struct buffered_reader *reader) {
SDL_assert(!reader->len);
ssize_t r = net_recv(reader->socket, reader->buf, reader->bufsize);
if (r > 0) {
reader->offset = 0;
reader->len = r;
}
return r;
}
ssize_t
buffered_reader_recv(struct buffered_reader *reader, void *buf, size_t count) {
if (!reader->len) {
// read from the socket
ssize_t r = buffered_reader_fill(reader);
if (r <= 0) {
return r;
}
}
size_t r = count < reader->len ? count : reader->len;
memcpy(buf, reader->buf + reader->offset, r);
reader->offset += r;
reader->len -= r;
return r;
}
ssize_t
buffered_reader_recv_all(struct buffered_reader *reader, void *buf,
size_t count) {
size_t done = 0;
while (done < count) {
ssize_t r = buffered_reader_recv(reader, buf, count - done);
if (r <= 0) {
// if there was some data, return them immediately
return done ? done : r;
}
done += r;
buf += r;
}
return done;
}

29
app/src/buffered_reader.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef BUFFERED_READER_H
#define BUFFERED_READER_H
#include "common.h"
#include "net.h"
struct buffered_reader {
socket_t socket;
void *buf;
size_t bufsize;
size_t offset;
size_t len;
};
bool
buffered_reader_init(struct buffered_reader *reader, socket_t socket,
size_t bufsize);
void
buffered_reader_destroy(struct buffered_reader *reader);
ssize_t
buffered_reader_recv(struct buffered_reader *reader, void *buf, size_t count);
ssize_t
buffered_reader_recv_all(struct buffered_reader *reader, void *buf,
size_t count);
#endif

View File

@ -6,7 +6,7 @@
#include <unistd.h> #include <unistd.h>
// To define a circular buffer type of 20 ints: // To define a circular buffer type of 20 ints:
// struct cbuf_int CBUF(int, 20); // typedef CBUF(int, 20) my_cbuf_t;
// //
// data has length CAP + 1 to distinguish empty vs full. // data has length CAP + 1 to distinguish empty vs full.
#define CBUF(TYPE, CAP) { \ #define CBUF(TYPE, CAP) { \
@ -35,7 +35,7 @@
(PCBUF)->head = ((PCBUF)->head + 1) % cbuf_size_(PCBUF); \ (PCBUF)->head = ((PCBUF)->head + 1) % cbuf_size_(PCBUF); \
} \ } \
ok; \ ok; \
}) }) \
#define cbuf_take(PCBUF, PITEM) \ #define cbuf_take(PCBUF, PITEM) \
({ \ ({ \

View File

@ -242,27 +242,16 @@ input_manager_process_key(struct input_manager *input_manager,
bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT); bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT);
bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI); bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI);
// use Cmd on macOS, Ctrl on other platforms
#ifdef __APPLE__
bool cmd = !ctrl && meta;
#else
if (meta) {
// no shortcuts involve Meta on platforms other than macOS, and it must
// not be forwarded to the device
return;
}
bool cmd = ctrl; // && !meta, already guaranteed
#endif
if (alt) { if (alt) {
// no shortcuts involve Alt, and it must not be forwarded to the device // no shortcut involves Alt or Meta, and they should not be forwarded
// to the device
return; return;
} }
struct controller *controller = input_manager->controller; struct controller *controller = input_manager->controller;
// capture all Ctrl events // capture all Ctrl events
if (ctrl || cmd) { if (ctrl | meta) {
SDL_Keycode keycode = event->keysym.sym; SDL_Keycode keycode = event->keysym.sym;
bool down = event->type == SDL_KEYDOWN; bool down = event->type == SDL_KEYDOWN;
int action = down ? ACTION_DOWN : ACTION_UP; int action = down ? ACTION_DOWN : ACTION_UP;
@ -270,59 +259,63 @@ input_manager_process_key(struct input_manager *input_manager,
bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT); bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT);
switch (keycode) { switch (keycode) {
case SDLK_h: case SDLK_h:
// Ctrl+h on all platform, since Cmd+h is already captured by
// the system on macOS to hide the window
if (control && ctrl && !meta && !shift && !repeat) { if (control && ctrl && !meta && !shift && !repeat) {
action_home(controller, action); action_home(controller, action);
} }
return; return;
case SDLK_b: // fall-through case SDLK_b: // fall-through
case SDLK_BACKSPACE: case SDLK_BACKSPACE:
if (control && cmd && !shift && !repeat) { if (control && ctrl && !meta && !shift && !repeat) {
action_back(controller, action); action_back(controller, action);
} }
return; return;
case SDLK_s: case SDLK_s:
if (control && cmd && !shift && !repeat) { if (control && ctrl && !meta && !shift && !repeat) {
action_app_switch(controller, action); action_app_switch(controller, action);
} }
return; return;
case SDLK_m: case SDLK_m:
// Ctrl+m on all platform, since Cmd+m is already captured by
// the system on macOS to minimize the window
if (control && ctrl && !meta && !shift && !repeat) { if (control && ctrl && !meta && !shift && !repeat) {
action_menu(controller, action); action_menu(controller, action);
} }
return; return;
case SDLK_p: case SDLK_p:
if (control && cmd && !shift && !repeat) { if (control && ctrl && !meta && !shift && !repeat) {
action_power(controller, action); action_power(controller, action);
} }
return; return;
case SDLK_o: case SDLK_o:
if (control && cmd && !shift && down) { if (control && ctrl && !shift && !meta && down) {
set_screen_power_mode(controller, SCREEN_POWER_MODE_OFF); set_screen_power_mode(controller, SCREEN_POWER_MODE_OFF);
} }
return; return;
case SDLK_DOWN: case SDLK_DOWN:
if (control && cmd && !shift) { #ifdef __APPLE__
if (control && !ctrl && meta && !shift) {
#else
if (control && ctrl && !meta && !shift) {
#endif
// forward repeated events // forward repeated events
action_volume_down(controller, action); action_volume_down(controller, action);
} }
return; return;
case SDLK_UP: case SDLK_UP:
if (control && cmd && !shift) { #ifdef __APPLE__
if (control && !ctrl && meta && !shift) {
#else
if (control && ctrl && !meta && !shift) {
#endif
// forward repeated events // forward repeated events
action_volume_up(controller, action); action_volume_up(controller, action);
} }
return; return;
case SDLK_c: case SDLK_c:
if (control && cmd && !shift && !repeat && down) { if (control && ctrl && !meta && !shift && !repeat && down) {
request_device_clipboard(controller); request_device_clipboard(controller);
} }
return; return;
case SDLK_v: case SDLK_v:
if (control && cmd && !repeat && down) { if (control && ctrl && !meta && !repeat && down) {
if (shift) { if (shift) {
// store the text in the device clipboard // store the text in the device clipboard
set_device_clipboard(controller); set_device_clipboard(controller);
@ -333,29 +326,29 @@ input_manager_process_key(struct input_manager *input_manager,
} }
return; return;
case SDLK_f: case SDLK_f:
if (!shift && cmd && !repeat && down) { if (ctrl && !meta && !shift && !repeat && down) {
screen_switch_fullscreen(input_manager->screen); screen_switch_fullscreen(input_manager->screen);
} }
return; return;
case SDLK_x: case SDLK_x:
if (!shift && cmd && !repeat && down) { if (ctrl && !meta && !shift && !repeat && down) {
screen_resize_to_fit(input_manager->screen); screen_resize_to_fit(input_manager->screen);
} }
return; return;
case SDLK_g: case SDLK_g:
if (!shift && cmd && !repeat && down) { if (ctrl && !meta && !shift && !repeat && down) {
screen_resize_to_pixel_perfect(input_manager->screen); screen_resize_to_pixel_perfect(input_manager->screen);
} }
return; return;
case SDLK_i: case SDLK_i:
if (!shift && cmd && !repeat && down) { if (ctrl && !meta && !shift && !repeat && down) {
struct fps_counter *fps_counter = struct fps_counter *fps_counter =
input_manager->video_buffer->fps_counter; input_manager->video_buffer->fps_counter;
switch_fps_counter_state(fps_counter); switch_fps_counter_state(fps_counter);
} }
return; return;
case SDLK_n: case SDLK_n:
if (control && cmd && !repeat && down) { if (control && ctrl && !meta && !repeat && down) {
if (shift) { if (shift) {
collapse_notification_panel(controller); collapse_notification_panel(controller);
} else { } else {

View File

@ -35,11 +35,6 @@ struct args {
}; };
static void usage(const char *arg0) { static void usage(const char *arg0) {
#ifdef __APPLE__
# define CTRL_OR_CMD "Cmd"
#else
# define CTRL_OR_CMD "Ctrl"
#endif
fprintf(stderr, fprintf(stderr,
"Usage: %s [options]\n" "Usage: %s [options]\n"
"\n" "\n"
@ -120,13 +115,13 @@ static void usage(const char *arg0) {
"\n" "\n"
"Shortcuts:\n" "Shortcuts:\n"
"\n" "\n"
" " CTRL_OR_CMD "+f\n" " Ctrl+f\n"
" switch fullscreen mode\n" " switch fullscreen mode\n"
"\n" "\n"
" " CTRL_OR_CMD "+g\n" " Ctrl+g\n"
" resize window to 1:1 (pixel-perfect)\n" " resize window to 1:1 (pixel-perfect)\n"
"\n" "\n"
" " CTRL_OR_CMD "+x\n" " Ctrl+x\n"
" Double-click on black borders\n" " Double-click on black borders\n"
" resize window to remove black borders\n" " resize window to remove black borders\n"
"\n" "\n"
@ -134,48 +129,48 @@ static void usage(const char *arg0) {
" Middle-click\n" " Middle-click\n"
" click on HOME\n" " click on HOME\n"
"\n" "\n"
" " CTRL_OR_CMD "+b\n" " Ctrl+b\n"
" " CTRL_OR_CMD "+Backspace\n" " Ctrl+Backspace\n"
" Right-click (when screen is on)\n" " Right-click (when screen is on)\n"
" click on BACK\n" " click on BACK\n"
"\n" "\n"
" " CTRL_OR_CMD "+s\n" " Ctrl+s\n"
" click on APP_SWITCH\n" " click on APP_SWITCH\n"
"\n" "\n"
" Ctrl+m\n" " Ctrl+m\n"
" click on MENU\n" " click on MENU\n"
"\n" "\n"
" " CTRL_OR_CMD "+Up\n" " Ctrl+Up\n"
" click on VOLUME_UP\n" " click on VOLUME_UP\n"
"\n" "\n"
" " CTRL_OR_CMD "+Down\n" " Ctrl+Down\n"
" click on VOLUME_DOWN\n" " click on VOLUME_DOWN\n"
"\n" "\n"
" " CTRL_OR_CMD "+p\n" " Ctrl+p\n"
" click on POWER (turn screen on/off)\n" " click on POWER (turn screen on/off)\n"
"\n" "\n"
" Right-click (when screen is off)\n" " Right-click (when screen is off)\n"
" power on\n" " power on\n"
"\n" "\n"
" " CTRL_OR_CMD "+o\n" " Ctrl+o\n"
" turn device screen off (keep mirroring)\n" " turn device screen off (keep mirroring)\n"
"\n" "\n"
" " CTRL_OR_CMD "+n\n" " Ctrl+n\n"
" expand notification panel\n" " expand notification panel\n"
"\n" "\n"
" " CTRL_OR_CMD "+Shift+n\n" " Ctrl+Shift+n\n"
" collapse notification panel\n" " collapse notification panel\n"
"\n" "\n"
" " CTRL_OR_CMD "+c\n" " Ctrl+c\n"
" copy device clipboard to computer\n" " copy device clipboard to computer\n"
"\n" "\n"
" " CTRL_OR_CMD "+v\n" " Ctrl+v\n"
" paste computer clipboard to device\n" " paste computer clipboard to device\n"
"\n" "\n"
" " CTRL_OR_CMD "+Shift+v\n" " Ctrl+Shift+v\n"
" copy computer clipboard to device\n" " copy computer clipboard to device\n"
"\n" "\n"
" " CTRL_OR_CMD "+i\n" " Ctrl+i\n"
" enable/disable FPS counter (print frames/second in logs)\n" " enable/disable FPS counter (print frames/second in logs)\n"
"\n" "\n"
" Drag & drop APK file\n" " Drag & drop APK file\n"

View File

@ -1,74 +0,0 @@
// generic intrusive FIFO queue
#ifndef QUEUE_H
#define QUEUE_H
#include <stdbool.h>
#include <SDL2/SDL_assert.h>
// To define a queue type of "struct foo":
// struct queue_foo QUEUE(struct foo);
#define QUEUE(TYPE) { \
TYPE *first; \
TYPE *last; \
}
#define queue_init(PQ) \
(void) ((PQ)->first = NULL)
#define queue_is_empty(PQ) \
!(PQ)->first
// NEXTFIELD is the field in the ITEM type used for intrusive linked-list
//
// For example:
// struct foo {
// int value;
// struct foo *next;
// };
//
// // define the type "struct my_queue"
// struct my_queue QUEUE(struct foo);
//
// struct my_queue queue;
// queue_init(&queue);
//
// struct foo v1 = { .value = 42 };
// struct foo v2 = { .value = 27 };
//
// queue_push(&queue, next, v1);
// queue_push(&queue, next, v2);
//
// struct foo *foo;
// queue_take(&queue, next, &foo);
// assert(foo->value == 42);
// queue_take(&queue, next, &foo);
// assert(foo->value == 27);
// assert(queue_is_empty(&queue));
//
// push a new item into the queue
#define queue_push(PQ, NEXTFIELD, ITEM) \
(void) ({ \
(ITEM)->NEXTFIELD = NULL; \
if (queue_is_empty(PQ)) { \
(PQ)->first = (PQ)->last = (ITEM); \
} else { \
(PQ)->last->NEXTFIELD = (ITEM); \
(PQ)->last = (ITEM); \
} \
})
// take the next item and remove it from the queue (the queue must not be empty)
// the result is stored in *(PITEM)
// (without typeof(), we could not store a local variable having the correct
// type so that we can "return" it)
#define queue_take(PQ, NEXTFIELD, PITEM) \
(void) ({ \
SDL_assert(!queue_is_empty(PQ)); \
*(PITEM) = (PQ)->first; \
(PQ)->first = (PQ)->first->NEXTFIELD; \
})
// no need to update (PQ)->last if the queue is left empty:
// (PQ)->last is undefined if !(PQ)->first anyway
#endif

View File

@ -37,6 +37,7 @@ record_packet_new(const AVPacket *packet) {
SDL_free(rec); SDL_free(rec);
return NULL; return NULL;
} }
rec->next = NULL;
return rec; return rec;
} }
@ -47,12 +48,59 @@ record_packet_delete(struct record_packet *rec) {
} }
static void static void
recorder_queue_clear(struct recorder_queue *queue) { recorder_queue_init(struct recorder_queue *queue) {
while (!queue_is_empty(queue)) { queue->first = NULL;
struct record_packet *rec; // queue->last is undefined if queue->first == NULL
queue_take(queue, next, &rec); }
record_packet_delete(rec);
static inline bool
recorder_queue_is_empty(struct recorder_queue *queue) {
return !queue->first;
}
static bool
recorder_queue_push(struct recorder_queue *queue, const AVPacket *packet) {
struct record_packet *rec = record_packet_new(packet);
if (!rec) {
LOGC("Could not allocate record packet");
return false;
} }
rec->next = NULL;
if (recorder_queue_is_empty(queue)) {
queue->first = queue->last = rec;
} else {
// chain rec after the (current) last packet
queue->last->next = rec;
// the last packet is now rec
queue->last = rec;
}
return true;
}
static inline struct record_packet *
recorder_queue_take(struct recorder_queue *queue) {
SDL_assert(!recorder_queue_is_empty(queue));
struct record_packet *rec = queue->first;
SDL_assert(rec);
queue->first = rec->next;
// no need to update queue->last if the queue is left empty:
// queue->last is undefined if queue->first == NULL
return rec;
}
static void
recorder_queue_clear(struct recorder_queue *queue) {
struct record_packet *rec = queue->first;
while (rec) {
struct record_packet *current = rec;
rec = rec->next;
record_packet_delete(current);
}
queue->first = NULL;
} }
bool bool
@ -81,7 +129,7 @@ recorder_init(struct recorder *recorder,
return false; return false;
} }
queue_init(&recorder->queue); recorder_queue_init(&recorder->queue);
recorder->stopped = false; recorder->stopped = false;
recorder->failed = false; recorder->failed = false;
recorder->format = format; recorder->format = format;
@ -248,20 +296,20 @@ run_recorder(void *data) {
for (;;) { for (;;) {
mutex_lock(recorder->mutex); mutex_lock(recorder->mutex);
while (!recorder->stopped && queue_is_empty(&recorder->queue)) { while (!recorder->stopped &&
recorder_queue_is_empty(&recorder->queue)) {
cond_wait(recorder->queue_cond, recorder->mutex); cond_wait(recorder->queue_cond, recorder->mutex);
} }
// if stopped is set, continue to process the remaining events (to // if stopped is set, continue to process the remaining events (to
// finish the recording) before actually stopping // finish the recording) before actually stopping
if (recorder->stopped && queue_is_empty(&recorder->queue)) { if (recorder->stopped && recorder_queue_is_empty(&recorder->queue)) {
mutex_unlock(recorder->mutex); mutex_unlock(recorder->mutex);
break; break;
} }
struct record_packet *rec; struct record_packet *rec = recorder_queue_take(&recorder->queue);
queue_take(&recorder->queue, next, &rec);
mutex_unlock(recorder->mutex); mutex_unlock(recorder->mutex);
@ -321,15 +369,9 @@ recorder_push(struct recorder *recorder, const AVPacket *packet) {
return false; return false;
} }
struct record_packet *rec = record_packet_new(packet); bool ok = recorder_queue_push(&recorder->queue, packet);
if (!rec) {
LOGC("Could not allocate record packet");
return false;
}
queue_push(&recorder->queue, next, rec);
cond_signal(recorder->queue_cond); cond_signal(recorder->queue_cond);
mutex_unlock(recorder->mutex); mutex_unlock(recorder->mutex);
return true; return ok;
} }

View File

@ -7,7 +7,6 @@
#include <SDL2/SDL_thread.h> #include <SDL2/SDL_thread.h>
#include "common.h" #include "common.h"
#include "queue.h"
enum recorder_format { enum recorder_format {
RECORDER_FORMAT_MP4 = 1, RECORDER_FORMAT_MP4 = 1,
@ -19,7 +18,10 @@ struct record_packet {
struct record_packet *next; struct record_packet *next;
}; };
struct recorder_queue QUEUE(struct record_packet); struct recorder_queue {
struct record_packet *first;
struct record_packet *last; // undefined if first is NULL
};
struct recorder { struct recorder {
char *filename; char *filename;

View File

@ -297,6 +297,7 @@ scrcpy(const struct scrcpy_options *options) {
bool video_buffer_initialized = false; bool video_buffer_initialized = false;
bool file_handler_initialized = false; bool file_handler_initialized = false;
bool recorder_initialized = false; bool recorder_initialized = false;
bool stream_initialized = false;
bool stream_started = false; bool stream_started = false;
bool controller_initialized = false; bool controller_initialized = false;
bool controller_started = false; bool controller_started = false;
@ -358,7 +359,10 @@ scrcpy(const struct scrcpy_options *options) {
av_log_set_callback(av_log_callback); av_log_set_callback(av_log_callback);
stream_init(&stream, server.video_socket, dec, rec); if (!stream_init(&stream, server.video_socket, dec, rec)) {
goto end;
}
stream_initialized = true;
// now we consumed the header values, the socket receives the video stream // now we consumed the header values, the socket receives the video stream
// start the stream // start the stream
@ -437,6 +441,9 @@ end:
if (stream_started) { if (stream_started) {
stream_join(&stream); stream_join(&stream);
} }
if (stream_initialized) {
stream_destroy(&stream);
}
if (controller_started) { if (controller_started) {
controller_join(&controller); controller_join(&controller);
} }

View File

@ -17,7 +17,7 @@
#include "log.h" #include "log.h"
#include "recorder.h" #include "recorder.h"
#define BUFSIZE 0x10000 #define STREAM_BUFSIZE 0x10000
#define HEADER_SIZE 12 #define HEADER_SIZE 12
#define NO_PTS UINT64_C(-1) #define NO_PTS UINT64_C(-1)
@ -37,7 +37,8 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) {
// It is followed by <packet_size> bytes containing the packet/frame. // It is followed by <packet_size> bytes containing the packet/frame.
uint8_t header[HEADER_SIZE]; uint8_t header[HEADER_SIZE];
ssize_t r = net_recv_all(stream->socket, header, HEADER_SIZE); ssize_t r =
buffered_reader_recv_all(&stream->buffered_reader, header, HEADER_SIZE);
if (r < HEADER_SIZE) { if (r < HEADER_SIZE) {
return false; return false;
} }
@ -51,7 +52,7 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) {
return false; return false;
} }
r = net_recv_all(stream->socket, packet->data, len); r = buffered_reader_recv_all(&stream->buffered_reader, packet->data, len);
if (r < len) { if (r < len) {
av_packet_unref(packet); av_packet_unref(packet);
return false; return false;
@ -267,13 +268,23 @@ end:
return 0; return 0;
} }
void bool
stream_init(struct stream *stream, socket_t socket, stream_init(struct stream *stream, socket_t socket,
struct decoder *decoder, struct recorder *recorder) { struct decoder *decoder, struct recorder *recorder) {
if (!buffered_reader_init(&stream->buffered_reader, socket,
STREAM_BUFSIZE)) {
return false;
}
stream->socket = socket; stream->socket = socket;
stream->decoder = decoder, stream->decoder = decoder,
stream->recorder = recorder; stream->recorder = recorder;
stream->has_pending = false; stream->has_pending = false;
return true;
}
void
stream_destroy(struct stream *stream) {
buffered_reader_destroy(&stream->buffered_reader);
} }
bool bool

View File

@ -7,12 +7,14 @@
#include <SDL2/SDL_atomic.h> #include <SDL2/SDL_atomic.h>
#include <SDL2/SDL_thread.h> #include <SDL2/SDL_thread.h>
#include "buffered_reader.h"
#include "net.h" #include "net.h"
struct video_buffer; struct video_buffer;
struct stream { struct stream {
socket_t socket; socket_t socket;
struct buffered_reader buffered_reader;
struct video_buffer *video_buffer; struct video_buffer *video_buffer;
SDL_Thread *thread; SDL_Thread *thread;
struct decoder *decoder; struct decoder *decoder;
@ -25,10 +27,13 @@ struct stream {
AVPacket pending; AVPacket pending;
}; };
void bool
stream_init(struct stream *stream, socket_t socket, stream_init(struct stream *stream, socket_t socket,
struct decoder *decoder, struct recorder *recorder); struct decoder *decoder, struct recorder *recorder);
void
stream_destroy(struct stream *stream);
bool bool
stream_start(struct stream *stream); stream_start(struct stream *stream);

View File

@ -1,38 +0,0 @@
#include <assert.h>
#include <queue.h>
struct foo {
int value;
struct foo *next;
};
static void test_queue(void) {
struct my_queue QUEUE(struct foo) queue;
queue_init(&queue);
assert(queue_is_empty(&queue));
struct foo v1 = { .value = 42 };
struct foo v2 = { .value = 27 };
queue_push(&queue, next, &v1);
queue_push(&queue, next, &v2);
struct foo *foo;
assert(!queue_is_empty(&queue));
queue_take(&queue, next, &foo);
assert(foo->value == 42);
assert(!queue_is_empty(&queue));
queue_take(&queue, next, &foo);
assert(foo->value == 27);
assert(queue_is_empty(&queue));
}
int main(void) {
test_queue();
return 0;
}