Pass video size as codec metadata

On initial connection, scrcpy sent some device metadata:
 - the device name (to be used as window title)
 - the initial video size (before any frame or even SPS/PPS)

But it is better to provide the initial video size as part as the video
stream, so that it can be demuxed and exposed via AVCodecContext to
sinks.

This avoids to pass an explicit "initial frame size" for the screen, the
recorder and the v4l2 sink.
This commit is contained in:
Romain Vimont
2023-03-11 09:21:49 +01:00
parent 3a72f3fb4d
commit 238ab872ba
17 changed files with 104 additions and 69 deletions

View File

@@ -239,7 +239,7 @@ sc_screen_update_content_rect(struct sc_screen *screen) {
}
}
static inline SDL_Texture *
static bool
create_texture(struct sc_screen *screen) {
SDL_Renderer *renderer = screen->renderer;
struct sc_size size = screen->frame_size;
@@ -247,7 +247,8 @@ create_texture(struct sc_screen *screen) {
SDL_TEXTUREACCESS_STREAMING,
size.width, size.height);
if (!texture) {
return NULL;
LOGE("Could not create texture: %s", SDL_GetError());
return false;
}
if (screen->mipmaps) {
@@ -263,7 +264,8 @@ create_texture(struct sc_screen *screen) {
SDL_GL_UnbindTexture(texture);
}
return texture;
screen->texture = texture;
return true;
}
// render the texture to the renderer
@@ -335,7 +337,25 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink,
(void) ctx;
struct sc_screen *screen = DOWNCAST(sink);
(void) screen;
assert(ctx->width > 0 && ctx->width <= 0xFFFF);
assert(ctx->height > 0 && ctx->height <= 0xFFFF);
// screen->frame_size is never used before the event is pushed, and the
// event acts as a memory barrier so it is safe without mutex
screen->frame_size.width = ctx->width;
screen->frame_size.height = ctx->height;
static SDL_Event event = {
.type = SC_EVENT_SCREEN_INIT_SIZE,
};
// Post the event on the UI thread (the texture must be created from there)
int ret = SDL_PushEvent(&event);
if (ret < 0) {
LOGW("Could not post init size event: %s", SDL_GetError());
return false;
}
#ifndef NDEBUG
screen->open = true;
#endif
@@ -410,14 +430,10 @@ sc_screen_init(struct sc_screen *screen,
goto error_destroy_frame_buffer;
}
screen->frame_size = params->frame_size;
screen->rotation = params->rotation;
if (screen->rotation) {
LOGI("Initial display rotation set to %u", screen->rotation);
}
struct sc_size content_size =
get_rotated_size(screen->frame_size, screen->rotation);
screen->content_size = content_size;
uint32_t window_flags = SDL_WINDOW_HIDDEN
| SDL_WINDOW_RESIZABLE
@@ -485,18 +501,10 @@ sc_screen_init(struct sc_screen *screen,
LOGW("Could not load icon");
}
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, params->frame_size.width,
params->frame_size.height);
screen->texture = create_texture(screen);
if (!screen->texture) {
LOGE("Could not create texture: %s", SDL_GetError());
goto error_destroy_renderer;
}
screen->frame = av_frame_alloc();
if (!screen->frame) {
LOG_OOM();
goto error_destroy_texture;
goto error_destroy_renderer;
}
struct sc_input_manager_params im_params = {
@@ -531,8 +539,6 @@ sc_screen_init(struct sc_screen *screen,
return true;
error_destroy_texture:
SDL_DestroyTexture(screen->texture);
error_destroy_renderer:
SDL_DestroyRenderer(screen->renderer);
error_destroy_window:
@@ -591,7 +597,9 @@ sc_screen_destroy(struct sc_screen *screen) {
assert(!screen->open);
#endif
av_frame_free(&screen->frame);
SDL_DestroyTexture(screen->texture);
if (screen->texture) {
SDL_DestroyTexture(screen->texture);
}
SDL_DestroyRenderer(screen->renderer);
SDL_DestroyWindow(screen->window);
sc_fps_counter_destroy(&screen->fps_counter);
@@ -655,6 +663,23 @@ sc_screen_set_rotation(struct sc_screen *screen, unsigned rotation) {
sc_screen_render(screen, true);
}
static bool
sc_screen_init_size(struct sc_screen *screen) {
// Before first frame
assert(!screen->has_frame);
assert(!screen->texture);
// The requested size is passed via screen->frame_size
struct sc_size content_size =
get_rotated_size(screen->frame_size, screen->rotation);
screen->content_size = content_size;
LOGI("Initial texture: %" PRIu16 "x%" PRIu16,
screen->frame_size.width, screen->frame_size.height);
return create_texture(screen);
}
// recreate the texture and resize the window if the frame size has changed
static bool
prepare_for_frame(struct sc_screen *screen, struct sc_size new_frame_size) {
@@ -673,11 +698,7 @@ prepare_for_frame(struct sc_screen *screen, struct sc_size new_frame_size) {
LOGI("New texture: %" PRIu16 "x%" PRIu16,
screen->frame_size.width, screen->frame_size.height);
screen->texture = create_texture(screen);
if (!screen->texture) {
LOGE("Could not create texture: %s", SDL_GetError());
return false;
}
return create_texture(screen);
}
return true;
@@ -795,6 +816,14 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
bool relative_mode = sc_screen_is_relative_mode(screen);
switch (event->type) {
case SC_EVENT_SCREEN_INIT_SIZE:
// The initial size is passed via screen->frame_size
bool ok = sc_screen_init_size(screen);
if (!ok) {
LOGE("Could not initialize screen size");
return false;
}
return true;
case SC_EVENT_NEW_FRAME: {
bool ok = sc_screen_update_frame(screen);
if (!ok) {