mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Signal client resize in session packets
So far, scrcpy always resized the window whenever a frame with a new size was received. However, with the upcoming "flex display" feature, the size of the virtual display can change either on its own (e.g., due to app rotation) or as a result of a client window resize. Track the cause of each resize and signal it in the session metadata. Resize the window only if the change was not triggered by a client request to prevent resize loops and stuttering.
This commit is contained in:
parent
160a378719
commit
3b068b669e
7 changed files with 61 additions and 24 deletions
|
|
@ -76,10 +76,10 @@ sc_demuxer_recv_header(struct sc_demuxer *demuxer,
|
|||
// which only contains a 12-byte header:
|
||||
//
|
||||
// byte 0 byte 1 byte 2 byte 3
|
||||
// 10000000 00000000 00000000 00000000
|
||||
// ^<-------------------------------->
|
||||
// | padding
|
||||
// `- session packet flag
|
||||
// 10000000 00000000 00000000 0000000.
|
||||
// ^<------------------------------->^
|
||||
// | padding |
|
||||
// `- session packet flag `- client resized flag
|
||||
//
|
||||
// byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 byte 10 byte 11
|
||||
// ........ ........ ........ ........ ........ ........ ........ ........
|
||||
|
|
@ -126,6 +126,7 @@ sc_demuxer_parse_session(const uint8_t *header,
|
|||
assert(sc_demuxer_is_session(header));
|
||||
session->video.width = sc_read32be(&header[4]);
|
||||
session->video.height = sc_read32be(&header[8]);
|
||||
session->video.client_resized = header[3] & 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
|||
|
|
@ -329,6 +329,8 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink,
|
|||
screen->content_size = get_oriented_size(screen->frame_size,
|
||||
screen->orientation);
|
||||
|
||||
screen->current_session = *session;
|
||||
|
||||
bool ok = sc_push_event(SC_EVENT_OPEN_WINDOW);
|
||||
if (!ok) {
|
||||
return false;
|
||||
|
|
@ -361,6 +363,7 @@ sc_screen_frame_sink_push(struct sc_frame_sink *sink, const AVFrame *frame) {
|
|||
sc_mutex_lock(&screen->mutex);
|
||||
bool previous_skipped = sc_frame_buffer_has_frame(&screen->fb);
|
||||
bool ok = sc_frame_buffer_push(&screen->fb, frame);
|
||||
screen->prevent_auto_resize = screen->current_session.video.client_resized;
|
||||
sc_mutex_unlock(&screen->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
|
|
@ -381,6 +384,14 @@ sc_screen_frame_sink_push(struct sc_frame_sink *sink, const AVFrame *frame) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
sc_screen_frame_sink_push_session(struct sc_frame_sink *sink,
|
||||
const struct sc_stream_session *session) {
|
||||
struct sc_screen *screen = DOWNCAST(sink);
|
||||
screen->current_session = *session;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sc_screen_init(struct sc_screen *screen,
|
||||
const struct sc_screen_params *params) {
|
||||
|
|
@ -403,6 +414,8 @@ sc_screen_init(struct sc_screen *screen,
|
|||
screen->req.fullscreen = params->fullscreen;
|
||||
screen->req.start_fps_counter = params->start_fps_counter;
|
||||
|
||||
screen->prevent_auto_resize = false;
|
||||
|
||||
bool ok = sc_mutex_init(&screen->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
|
|
@ -570,10 +583,13 @@ sc_screen_init(struct sc_screen *screen,
|
|||
}
|
||||
#endif
|
||||
|
||||
memset(&screen->current_session, 0, sizeof(screen->current_session));
|
||||
|
||||
static const struct sc_frame_sink_ops ops = {
|
||||
.open = sc_screen_frame_sink_open,
|
||||
.close = sc_screen_frame_sink_close,
|
||||
.push = sc_screen_frame_sink_push,
|
||||
.push_session = sc_screen_frame_sink_push_session,
|
||||
};
|
||||
|
||||
screen->frame_sink.ops = &ops;
|
||||
|
|
@ -725,16 +741,19 @@ resize_for_content(struct sc_screen *screen, struct sc_size old_content_size,
|
|||
}
|
||||
|
||||
static void
|
||||
set_content_size(struct sc_screen *screen, struct sc_size new_content_size) {
|
||||
set_content_size(struct sc_screen *screen, struct sc_size new_content_size,
|
||||
bool resize) {
|
||||
assert(screen->video);
|
||||
|
||||
if (is_windowed(screen)) {
|
||||
resize_for_content(screen, screen->content_size, new_content_size);
|
||||
} else if (!screen->resize_pending) {
|
||||
// Store the windowed size to be able to compute the optimal size once
|
||||
// fullscreen/maximized/minimized are disabled
|
||||
screen->windowed_content_size = screen->content_size;
|
||||
screen->resize_pending = true;
|
||||
if (resize) {
|
||||
if (is_windowed(screen)) {
|
||||
resize_for_content(screen, screen->content_size, new_content_size);
|
||||
} else if (!screen->resize_pending) {
|
||||
// Store the windowed size to be able to compute the optimal size
|
||||
// once fullscreen/maximized/minimized are disabled
|
||||
screen->windowed_content_size = screen->content_size;
|
||||
screen->resize_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
screen->content_size = new_content_size;
|
||||
|
|
@ -764,7 +783,7 @@ sc_screen_set_orientation(struct sc_screen *screen,
|
|||
struct sc_size new_content_size =
|
||||
get_oriented_size(screen->frame_size, orientation);
|
||||
|
||||
set_content_size(screen, new_content_size);
|
||||
set_content_size(screen, new_content_size, true);
|
||||
|
||||
screen->orientation = orientation;
|
||||
LOGI("Display orientation set to %s", sc_orientation_get_name(orientation));
|
||||
|
|
@ -773,7 +792,7 @@ sc_screen_set_orientation(struct sc_screen *screen,
|
|||
}
|
||||
|
||||
static bool
|
||||
sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
sc_screen_apply_frame(struct sc_screen *screen, bool can_resize) {
|
||||
assert(screen->video);
|
||||
assert(screen->window_shown);
|
||||
|
||||
|
|
@ -790,7 +809,7 @@ sc_screen_apply_frame(struct sc_screen *screen) {
|
|||
|
||||
struct sc_size new_content_size =
|
||||
get_oriented_size(new_frame_size, screen->orientation);
|
||||
set_content_size(screen, new_content_size);
|
||||
set_content_size(screen, new_content_size, can_resize);
|
||||
sc_screen_update_content_rect(screen);
|
||||
}
|
||||
|
||||
|
|
@ -826,8 +845,10 @@ sc_screen_update_frame(struct sc_screen *screen) {
|
|||
av_frame_unref(screen->frame);
|
||||
sc_mutex_lock(&screen->mutex);
|
||||
sc_frame_buffer_consume(&screen->fb, screen->frame);
|
||||
// read with lock held
|
||||
bool can_resize = !screen->prevent_auto_resize;
|
||||
sc_mutex_unlock(&screen->mutex);
|
||||
return sc_screen_apply_frame(screen);
|
||||
return sc_screen_apply_frame(screen, can_resize);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -845,7 +866,7 @@ sc_screen_set_paused(struct sc_screen *screen, bool paused) {
|
|||
av_frame_free(&screen->frame);
|
||||
screen->frame = screen->resume_frame;
|
||||
screen->resume_frame = NULL;
|
||||
bool ok = sc_screen_apply_frame(screen);
|
||||
bool ok = sc_screen_apply_frame(screen, true);
|
||||
if (!ok) {
|
||||
LOGE("Resume frame update failed");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ struct sc_screen {
|
|||
|
||||
struct sc_mutex mutex;
|
||||
struct sc_frame_buffer fb; // protected by mutex
|
||||
// When true, a frame size change must not cause the window to be resized
|
||||
bool prevent_auto_resize; // protected by mutex
|
||||
|
||||
// The initial requested window properties
|
||||
struct {
|
||||
|
|
@ -77,6 +79,9 @@ struct sc_screen {
|
|||
struct SDL_FRect rect;
|
||||
bool window_shown;
|
||||
|
||||
// only accessed from the thread calling sc_frame_sink_ops functions
|
||||
struct sc_stream_session current_session;
|
||||
|
||||
AVFrame *frame;
|
||||
|
||||
bool paused;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ struct sc_packet_sink {
|
|||
struct sc_stream_session_video {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
bool client_resized;
|
||||
};
|
||||
|
||||
struct sc_stream_session {
|
||||
|
|
|
|||
|
|
@ -370,10 +370,10 @@ session (a session changes when the device rotates):
|
|||
|
||||
```
|
||||
byte 0 byte 1 byte 2 byte 3
|
||||
10000000 00000000 00000000 00000000
|
||||
^<-------------------------------->
|
||||
| padding
|
||||
`- session packet flag
|
||||
10000000 00000000 00000000 0000000.
|
||||
^<------------------------------->^
|
||||
| padding |
|
||||
`- session packet flag `- client resized flag
|
||||
|
||||
byte 4 byte 5 byte 6 byte 7 byte 8 byte 9 byte 10 byte 11
|
||||
........ ........ ........ ........ ........ ........ ........ ........
|
||||
|
|
@ -381,6 +381,11 @@ session (a session changes when the device rotates):
|
|||
video width video height
|
||||
```
|
||||
|
||||
The "client resized" flag is used for _flex displays_ to indicate that the frame
|
||||
size changed due to a client resize request (see [#6772]).
|
||||
|
||||
[#6772]: https://github.com/Genymobile/scrcpy/pull/6772
|
||||
|
||||
For the _audio_ stream, there are no _session packets_.
|
||||
|
||||
Then _media packets_ are sent, each containing the payload produced by
|
||||
|
|
|
|||
|
|
@ -88,11 +88,15 @@ public final class Streamer {
|
|||
writePacket(codecBuffer, pts, config, keyFrame);
|
||||
}
|
||||
|
||||
public void writeSessionMeta(int width, int height) throws IOException {
|
||||
public void writeSessionMeta(int width, int height, boolean clientResize) throws IOException {
|
||||
if (sendStreamMeta) {
|
||||
headerBuffer.clear();
|
||||
|
||||
headerBuffer.putInt((int) (PACKET_FLAG_SESSION >> 32)); // Set the first bit to 1
|
||||
int flags = (int) (PACKET_FLAG_SESSION >> 32); // set the first bit to 1
|
||||
if (clientResize) {
|
||||
flags |= 1;
|
||||
}
|
||||
headerBuffer.putInt(flags);
|
||||
headerBuffer.putInt(width);
|
||||
headerBuffer.putInt(height);
|
||||
headerBuffer.flip();
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ public class SurfaceEncoder implements AsyncProcessor {
|
|||
} else {
|
||||
if (!captureControl.isResetRequested()) {
|
||||
// If a reset is requested during encode(), it will interrupt the encoding by an EOS
|
||||
streamer.writeSessionMeta(size.getWidth(), size.getHeight());
|
||||
streamer.writeSessionMeta(size.getWidth(), size.getHeight(), false);
|
||||
encode(mediaCodec, streamer);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue