Milestone, fix black screen and initial frame issues
This commit is contained in:
parent
f4fa723863
commit
0a250b05f3
11 changed files with 708 additions and 47 deletions
128
src/app.c
128
src/app.c
|
|
@ -1,9 +1,57 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "app.h"
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void configure_runtime_environment(void) {
|
||||
char runtime_dir[64];
|
||||
char pulse_socket[96];
|
||||
const char *display;
|
||||
|
||||
if (!getenv("XDG_RUNTIME_DIR") || getenv("XDG_RUNTIME_DIR")[0] == '\0') {
|
||||
snprintf(runtime_dir, sizeof(runtime_dir), "/run/user/%u", (unsigned int) getuid());
|
||||
if (access(runtime_dir, R_OK | W_OK | X_OK) == 0) {
|
||||
setenv("XDG_RUNTIME_DIR", runtime_dir, 1);
|
||||
}
|
||||
}
|
||||
|
||||
display = getenv("DISPLAY");
|
||||
if ((!display || display[0] == '\0') && access("/tmp/.X11-unix/X0", R_OK | W_OK) == 0) {
|
||||
setenv("DISPLAY", ":0", 1);
|
||||
}
|
||||
|
||||
if (getenv("XDG_RUNTIME_DIR") && getenv("XDG_RUNTIME_DIR")[0] != '\0' &&
|
||||
(!getenv("PULSE_SERVER") || getenv("PULSE_SERVER")[0] == '\0')) {
|
||||
snprintf(pulse_socket, sizeof(pulse_socket), "%s/pulse/native", getenv("XDG_RUNTIME_DIR"));
|
||||
if (access(pulse_socket, R_OK | W_OK) == 0) {
|
||||
setenv("PULSE_SERVER", pulse_socket, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void log_runtime_environment(const char *phase) {
|
||||
const char *display = getenv("DISPLAY");
|
||||
const char *wayland_display = getenv("WAYLAND_DISPLAY");
|
||||
const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
|
||||
const char *pulse_server = getenv("PULSE_SERVER");
|
||||
const char *video_driver = SDL_GetCurrentVideoDriver();
|
||||
|
||||
fprintf(stderr,
|
||||
"%s: DISPLAY=%s WAYLAND_DISPLAY=%s XDG_RUNTIME_DIR=%s PULSE_SERVER=%s SDL_VIDEODRIVER=%s\n",
|
||||
phase ? phase : "startup",
|
||||
display && display[0] != '\0' ? display : "<unset>",
|
||||
wayland_display && wayland_display[0] != '\0' ? wayland_display : "<unset>",
|
||||
runtime_dir && runtime_dir[0] != '\0' ? runtime_dir : "<unset>",
|
||||
pulse_server && pulse_server[0] != '\0' ? pulse_server : "<unset>",
|
||||
video_driver && video_driver[0] != '\0' ? video_driver : "<pending>");
|
||||
}
|
||||
|
||||
static void destroy_video_texture(App *app) {
|
||||
if (app->video_texture) {
|
||||
SDL_DestroyTexture(app->video_texture);
|
||||
|
|
@ -13,17 +61,33 @@ static void destroy_video_texture(App *app) {
|
|||
}
|
||||
}
|
||||
|
||||
static void begin_startup_handoff(App *app) {
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
app->startup_handoff_active = 1;
|
||||
app->startup_handoff_until = 0;
|
||||
}
|
||||
|
||||
static int update_video_texture(App *app) {
|
||||
FrameData frame = {0};
|
||||
double sync_clock;
|
||||
double lead_tolerance;
|
||||
|
||||
if (!player_consume_latest_frame(&app->player, &frame)) {
|
||||
return 0;
|
||||
sync_clock = player_get_sync_clock(&app->player, time(NULL));
|
||||
lead_tolerance = app->startup_handoff_active ? 0.220 : 0.035;
|
||||
|
||||
if (!player_consume_synced_frame(&app->player, &frame, sync_clock, lead_tolerance)) {
|
||||
if (!app->startup_handoff_active || !player_consume_latest_frame(&app->player, &frame)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!app->video_texture || app->texture_width != frame.width || app->texture_height != frame.height) {
|
||||
destroy_video_texture(app);
|
||||
app->video_texture = SDL_CreateTexture(app->renderer,
|
||||
SDL_PIXELFORMAT_RGBA32,
|
||||
SDL_PIXELFORMAT_IYUV,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
frame.width,
|
||||
frame.height);
|
||||
|
|
@ -36,14 +100,22 @@ static int update_video_texture(App *app) {
|
|||
SDL_SetTextureBlendMode(app->video_texture, SDL_BLENDMODE_NONE);
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(app->video_texture, NULL, frame.pixels, frame.stride);
|
||||
SDL_UpdateYUVTexture(app->video_texture,
|
||||
NULL,
|
||||
frame.plane_y,
|
||||
frame.pitch_y,
|
||||
frame.plane_u,
|
||||
frame.pitch_u,
|
||||
frame.plane_v,
|
||||
frame.pitch_v);
|
||||
frame_data_free(&frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void render_black(App *app) {
|
||||
SDL_SetRenderDrawColor(app->renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(app->renderer);
|
||||
if (app->startup_handoff_active && app->startup_handoff_until != 0 && SDL_GetTicks() >= app->startup_handoff_until) {
|
||||
app->startup_handoff_active = 0;
|
||||
app->startup_handoff_until = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tune_relative(App *app, int delta) {
|
||||
|
|
@ -58,6 +130,8 @@ static void tune_relative(App *app, int delta) {
|
|||
next_index = 0;
|
||||
}
|
||||
next_index = (next_index + delta + app->channels.count) % app->channels.count;
|
||||
destroy_video_texture(app);
|
||||
begin_startup_handoff(app);
|
||||
player_tune(&app->player, next_index);
|
||||
}
|
||||
|
||||
|
|
@ -97,13 +171,23 @@ int app_init(App *app) {
|
|||
memset(app, 0, sizeof(*app));
|
||||
app->running = 1;
|
||||
app->mode = MODE_FULLSCREEN;
|
||||
app->last_blackout_state = 1;
|
||||
app->app_start_time = time(NULL);
|
||||
|
||||
configure_runtime_environment();
|
||||
log_runtime_environment("startup-before-sdl");
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0) {
|
||||
fprintf(stderr, "SDL init failed: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_runtime_environment("startup-after-sdl");
|
||||
if (SDL_GetCurrentVideoDriver() && strcmp(SDL_GetCurrentVideoDriver(), "offscreen") == 0) {
|
||||
fprintf(stderr, "SDL selected offscreen video driver unexpectedly; refusing to continue without a visible display.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TTF_Init() != 0) {
|
||||
fprintf(stderr, "SDL_ttf init failed: %s\n", TTF_GetError());
|
||||
return -1;
|
||||
|
|
@ -138,6 +222,7 @@ int app_init(App *app) {
|
|||
}
|
||||
|
||||
if (app->channels.count > 0) {
|
||||
begin_startup_handoff(app);
|
||||
player_tune(&app->player, 0);
|
||||
}
|
||||
|
||||
|
|
@ -148,6 +233,8 @@ void app_run(App *app) {
|
|||
SDL_Event event;
|
||||
|
||||
while (app->running) {
|
||||
int in_blackout;
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
handle_event(app, &event);
|
||||
}
|
||||
|
|
@ -157,13 +244,22 @@ void app_run(App *app) {
|
|||
break;
|
||||
}
|
||||
|
||||
in_blackout = player_is_in_blackout(&app->player);
|
||||
if (app->last_blackout_state && !in_blackout) {
|
||||
app->startup_handoff_active = 1;
|
||||
app->startup_handoff_until = SDL_GetTicks() + 400;
|
||||
player_set_catchup_until(&app->player, app->startup_handoff_until);
|
||||
}
|
||||
app->last_blackout_state = in_blackout;
|
||||
|
||||
if (app->channels.count == 0) {
|
||||
ui_render_no_media(app->renderer, &app->fonts);
|
||||
} else if (player_is_in_blackout(&app->player)) {
|
||||
render_black(app);
|
||||
} else if (app->mode == MODE_GUIDE) {
|
||||
if (!in_blackout) {
|
||||
player_resume_audio(&app->player);
|
||||
}
|
||||
ui_render_guide(app->renderer,
|
||||
app->video_texture,
|
||||
in_blackout ? NULL : app->video_texture,
|
||||
app->texture_width,
|
||||
app->texture_height,
|
||||
&app->fonts,
|
||||
|
|
@ -172,7 +268,13 @@ void app_run(App *app) {
|
|||
app->app_start_time,
|
||||
time(NULL));
|
||||
} else {
|
||||
ui_render_fullscreen(app->renderer, app->video_texture, app->texture_width, app->texture_height);
|
||||
if (!in_blackout) {
|
||||
player_resume_audio(&app->player);
|
||||
}
|
||||
ui_render_fullscreen(app->renderer,
|
||||
in_blackout ? NULL : app->video_texture,
|
||||
app->texture_width,
|
||||
app->texture_height);
|
||||
}
|
||||
|
||||
SDL_RenderPresent(app->renderer);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue