Compare commits

..

24 Commits

Author SHA1 Message Date
Romain Vimont
7fa922d8e6 Hide the window immediately on close
The screen may not be destroyed immediately on close to avoid undefined
behavior, because it may still receive events from the decoder.

But the visual window must still be closed immediately.
2021-04-13 22:37:08 +02:00
Romain Vimont
ac7dca42b0 Assert screen closed on destroy
The destruction order is important, but tricky, because the screen is
open/close by the decoder, but destroyed by scrcpy.c on the main thread.

Add assertions to guarantee that the screen is not destroyed before
being closed.
2021-04-13 22:37:08 +02:00
Romain Vimont
492162a24f Remove video_buffer callbacks
Now that screen is both the owner and the listener of the video buffer,
execute the code directly without callbacks.
2021-04-13 22:37:08 +02:00
Romain Vimont
2ab148bd79 Move video_buffer to screen
The video buffer is now an internal detail of the screen component.

Since the screen is plugged to the decoder via the frame sink trait, the
decoder does not access to the video buffer anymore.
2021-04-13 22:37:08 +02:00
Romain Vimont
6795564044 Make decoder push frames to sinks
Now that screen implements the packet sink trait, make decoder push
packets to the sinks without depending on the concrete sink types.
2021-04-13 22:37:08 +02:00
Romain Vimont
b7cdbce8e5 Expose screen as frame sink
Make screen implement the frame sink trait.

This will allow the decoder to push frames without depending on the
concrete sink type.
2021-04-13 22:37:08 +02:00
Romain Vimont
5cd847a856 Add frame sink trait
This trait will allow to abstract the concrete sink types from the frame
producer (decoder.c).
2021-04-13 22:37:08 +02:00
Romain Vimont
3d36915d9b Make stream push packets to sinks
Now that decoder and recorder implement the packet sink trait, make
stream push packets to the sinks without depending on the concrete sink
types.
2021-04-13 22:37:08 +02:00
Romain Vimont
c64f5ff71e Expose decoder as packet sink
Make decoder implement the packet sink trait.

This will allow the stream to push packets without depending on the
concrete sink type.
2021-04-13 22:37:08 +02:00
Romain Vimont
db418d0825 Reorder decoder functions
This will make further commits more readable.
2021-04-13 22:37:08 +02:00
Romain Vimont
b481ab0aaf Expose recorder as packet sink
Make recorder implement the packet sink trait.

This will allow the stream to push packets without depending on the
concrete sink type.
2021-04-13 22:37:08 +02:00
Romain Vimont
cb7017e2c1 Privatize recorder threading
The fact that the recorder uses a separate thread is an internal detail,
so the functions _start(), _stop() and _join() should not be exposed.

Instead, start the thread on _open() and _stop()+_join() on close().

This paves the way to expose the recorder as a packet sink trait.
2021-04-13 22:37:08 +02:00
Romain Vimont
5c6b04cf01 Reorder recorder functions
This will make further commits more readable.
2021-04-13 22:37:08 +02:00
Romain Vimont
153d5e4892 Add packet sink trait
This trait will allow to abstract the concrete sink types from the
packet producer (stream.c).
2021-04-13 22:37:08 +02:00
Romain Vimont
620b117a15 Add container_of() macro
This will allow to get the parent of an embedded struct.
2021-04-13 22:37:08 +02:00
Romain Vimont
14e83175a6 Make video_buffer more generic
The video buffer took ownership of the producer frame (so that it could
swap frames quickly).

In order to support multiple sinks plugged to the decoder, the decoded
frame must not be consumed by the display video buffer.

Therefore, move the producer and consumer frames out of the video
buffer, and use FFmpeg AVFrame refcounting to share ownership while
avoiding copies.
2021-04-13 22:37:08 +02:00
Romain Vimont
0d46d0b376 Remove compat with old FFmpeg codec params API
The new API has been introduced in 2016 in libavformat 57.xx, it's very
old.

This will avoid to maintain two code paths for codec parameters.
2021-04-13 22:37:08 +02:00
Romain Vimont
4632ef224c Remove compat with old FFmpeg decoding API
The new API has been introduced in 2016 in libavcodec 57.xx, it's very
old.

This will avoid to maintain two code paths for decoding.
2021-04-13 22:37:08 +02:00
Romain Vimont
bc07943624 Remove option --render-expired-frames
This flag forced the decoder to wait for the previous frame to be
consumed by the display.

It was initially implemented as a compilation flag for testing, not
intended to be exposed at runtime. But to remove ifdefs and to allow
users to test this flag easily, it had finally been exposed by commit
ebccb9f6cc.

In practice, it turned out to be useless: it had no practical impact,
and it did not solve or mitigate any performance issues causing frame
skipping.

But that added some complexity to the codebase: it required an
additional condition variable, and made video buffer calls possibly
blocking, which in turn required code to interrupt it on exit.

To prepare support for multiple sinks plugged to the decoder (display
and v4l2 for example), the blocking call used for pacing the decoder
output becomes unacceptable, so just remove this useless "feature".
2021-04-13 22:37:08 +02:00
Romain Vimont
003fcb0442 Write trailer from recorder thread
The recorder thread wrote the whole content except the trailer, which
was odd.
2021-04-13 22:37:08 +02:00
Romain Vimont
8ef4c044fa Do not forward SDL_DROPFILE event
The event is handled by scrcpy.c, it is not necessary to send it to
screen or input_manager.
2021-04-13 22:37:08 +02:00
Romain Vimont
c23c38f99d Move resizing workaround to screen.c 2021-04-13 22:36:59 +02:00
Romain Vimont
65c4f487b3 Set initial fullscreen from screen.c 2021-04-13 22:15:05 +02:00
Romain Vimont
c6d7f5ee96 Make screen_show_window() static
It is only used from screen.c now.
2021-04-13 22:04:38 +02:00
3 changed files with 52 additions and 39 deletions

View File

@@ -126,30 +126,6 @@ sdl_init_and_configure(bool display, const char *render_driver,
return true;
}
#if defined(__APPLE__) || defined(__WINDOWS__)
# define CONTINUOUS_RESIZING_WORKAROUND
#endif
#ifdef CONTINUOUS_RESIZING_WORKAROUND
// On Windows and MacOS, resizing blocks the event loop, so resizing events are
// not triggered. As a workaround, handle them in an event handler.
//
// <https://bugzilla.libsdl.org/show_bug.cgi?id=2077>
// <https://stackoverflow.com/a/40693139/1987178>
static int
event_watcher(void *data, SDL_Event *event) {
(void) data;
if (event->type == SDL_WINDOWEVENT
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
// In practice, it seems to always be called from the same thread in
// that specific case. Anyway, it's just a workaround.
screen_render(&screen, true);
}
return 0;
}
#endif
static bool
is_apk(const char *file) {
const char *ext = strrchr(file, '.');
@@ -189,7 +165,7 @@ handle_event(SDL_Event *event, const struct scrcpy_options *options) {
action = ACTION_PUSH_FILE;
}
file_handler_request(&file_handler, action, file);
break;
goto end;
}
}
@@ -207,11 +183,6 @@ end:
static bool
event_loop(const struct scrcpy_options *options) {
#ifdef CONTINUOUS_RESIZING_WORKAROUND
if (options->display) {
SDL_AddEventWatch(event_watcher, NULL);
}
#endif
SDL_Event event;
while (SDL_WaitEvent(&event)) {
enum event_result result = handle_event(&event, options);
@@ -394,6 +365,7 @@ scrcpy(const struct scrcpy_options *options) {
.window_borderless = options->window_borderless,
.rotation = options->rotation,
.mipmaps = options->mipmaps,
.fullscreen = options->fullscreen,
};
if (!screen_init(&screen, &fps_counter, &screen_params)) {
@@ -412,10 +384,6 @@ scrcpy(const struct scrcpy_options *options) {
LOGW("Could not request 'set screen power mode'");
}
}
if (options->fullscreen) {
screen_switch_fullscreen(&screen);
}
}
// now we consumed the header values, the socket receives the video stream
@@ -430,6 +398,10 @@ scrcpy(const struct scrcpy_options *options) {
ret = event_loop(options);
LOGD("quit...");
// Close the window immediately on closing, because screen_destroy() may
// only be called once the stream thread is joined (it may take time)
screen_hide_window(&screen);
end:
// The stream is not stopped explicitly, because it will stop by itself on
// end-of-stream

View File

@@ -220,6 +220,29 @@ create_texture(struct screen *screen) {
return texture;
}
#if defined(__APPLE__) || defined(__WINDOWS__)
# define CONTINUOUS_RESIZING_WORKAROUND
#endif
#ifdef CONTINUOUS_RESIZING_WORKAROUND
// On Windows and MacOS, resizing blocks the event loop, so resizing events are
// not triggered. As a workaround, handle them in an event handler.
//
// <https://bugzilla.libsdl.org/show_bug.cgi?id=2077>
// <https://stackoverflow.com/a/40693139/1987178>
static int
event_watcher(void *data, SDL_Event *event) {
struct screen *screen = data;
if (event->type == SDL_WINDOWEVENT
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
// In practice, it seems to always be called from the same thread in
// that specific case. Anyway, it's just a workaround.
screen_render(screen, true);
}
return 0;
}
#endif
static bool
screen_frame_sink_open(struct sc_frame_sink *sink) {
struct screen *screen = DOWNCAST(sink);
@@ -402,6 +425,14 @@ screen_init(struct screen *screen, struct fps_counter *fps_counter,
screen_update_content_rect(screen);
if (params->fullscreen) {
screen_switch_fullscreen(screen);
}
#ifdef CONTINUOUS_RESIZING_WORKAROUND
SDL_AddEventWatch(event_watcher, screen);
#endif
static const struct sc_frame_sink_ops ops = {
.open = screen_frame_sink_open,
.close = screen_frame_sink_close,
@@ -417,11 +448,16 @@ screen_init(struct screen *screen, struct fps_counter *fps_counter,
return true;
}
void
static void
screen_show_window(struct screen *screen) {
SDL_ShowWindow(screen->window);
}
void
screen_hide_window(struct screen *screen) {
SDL_HideWindow(screen->window);
}
void
screen_destroy(struct screen *screen) {
#ifndef NDEBUG

View File

@@ -62,6 +62,8 @@ struct screen_params {
uint8_t rotation;
bool mipmaps;
bool fullscreen;
};
// initialize screen, create window, renderer and texture (window is hidden)
@@ -69,14 +71,17 @@ bool
screen_init(struct screen *screen, struct fps_counter *fps_counter,
const struct screen_params *params);
// show the window
void
screen_show_window(struct screen *screen);
// destroy window, renderer and texture (if any)
void
screen_destroy(struct screen *screen);
// hide the window
//
// It is used to hide the window immediately on closing without waiting for
// screen_destroy()
void
screen_hide_window(struct screen *screen);
// render the texture to the renderer
//
// Set the update_content_rect flag if the window or content size may have