Initial Commit
This commit is contained in:
commit
f4fa723863
22 changed files with 1402 additions and 0 deletions
199
src/app.c
Normal file
199
src/app.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
#include "app.h"
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void destroy_video_texture(App *app) {
|
||||
if (app->video_texture) {
|
||||
SDL_DestroyTexture(app->video_texture);
|
||||
app->video_texture = NULL;
|
||||
app->texture_width = 0;
|
||||
app->texture_height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int update_video_texture(App *app) {
|
||||
FrameData frame = {0};
|
||||
|
||||
if (!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_TEXTUREACCESS_STREAMING,
|
||||
frame.width,
|
||||
frame.height);
|
||||
if (!app->video_texture) {
|
||||
frame_data_free(&frame);
|
||||
return -1;
|
||||
}
|
||||
app->texture_width = frame.width;
|
||||
app->texture_height = frame.height;
|
||||
SDL_SetTextureBlendMode(app->video_texture, SDL_BLENDMODE_NONE);
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(app->video_texture, NULL, frame.pixels, frame.stride);
|
||||
frame_data_free(&frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void render_black(App *app) {
|
||||
SDL_SetRenderDrawColor(app->renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(app->renderer);
|
||||
}
|
||||
|
||||
static void tune_relative(App *app, int delta) {
|
||||
int next_index;
|
||||
|
||||
if (app->channels.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
next_index = app->player.current_index;
|
||||
if (next_index < 0) {
|
||||
next_index = 0;
|
||||
}
|
||||
next_index = (next_index + delta + app->channels.count) % app->channels.count;
|
||||
player_tune(&app->player, next_index);
|
||||
}
|
||||
|
||||
static void handle_event(App *app, const SDL_Event *event) {
|
||||
if (event->type == SDL_QUIT) {
|
||||
app->running = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->type != SDL_KEYDOWN || event->key.repeat) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
if (app->mode == MODE_GUIDE) {
|
||||
app->mode = MODE_FULLSCREEN;
|
||||
} else {
|
||||
app->running = 0;
|
||||
}
|
||||
break;
|
||||
case SDLK_TAB:
|
||||
app->mode = app->mode == MODE_FULLSCREEN ? MODE_GUIDE : MODE_FULLSCREEN;
|
||||
break;
|
||||
case SDLK_UP:
|
||||
tune_relative(app, -1);
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
tune_relative(app, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int app_init(App *app) {
|
||||
memset(app, 0, sizeof(*app));
|
||||
app->running = 1;
|
||||
app->mode = MODE_FULLSCREEN;
|
||||
app->app_start_time = time(NULL);
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0) {
|
||||
fprintf(stderr, "SDL init failed: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TTF_Init() != 0) {
|
||||
fprintf(stderr, "SDL_ttf init failed: %s\n", TTF_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
app->window = SDL_CreateWindow("Passport-C Media Player",
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
WINDOW_WIDTH,
|
||||
WINDOW_HEIGHT,
|
||||
SDL_WINDOW_SHOWN);
|
||||
app->renderer = SDL_CreateRenderer(app->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
|
||||
if (!app->window || !app->renderer) {
|
||||
fprintf(stderr, "SDL window or renderer creation failed: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ui_load_fonts(&app->fonts) != 0) {
|
||||
fprintf(stderr, "Unable to load a fallback font.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channel_list_load(&app->channels, "./media") < 0) {
|
||||
fprintf(stderr, "Unable to scan ./media.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (player_init(&app->player, &app->channels, app->app_start_time) != 0) {
|
||||
fprintf(stderr, "Unable to initialize player.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (app->channels.count > 0) {
|
||||
player_tune(&app->player, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void app_run(App *app) {
|
||||
SDL_Event event;
|
||||
|
||||
while (app->running) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
handle_event(app, &event);
|
||||
}
|
||||
|
||||
if (update_video_texture(app) != 0) {
|
||||
app->running = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
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) {
|
||||
ui_render_guide(app->renderer,
|
||||
app->video_texture,
|
||||
app->texture_width,
|
||||
app->texture_height,
|
||||
&app->fonts,
|
||||
&app->channels,
|
||||
app->player.current_index,
|
||||
app->app_start_time,
|
||||
time(NULL));
|
||||
} else {
|
||||
ui_render_fullscreen(app->renderer, app->video_texture, app->texture_width, app->texture_height);
|
||||
}
|
||||
|
||||
SDL_RenderPresent(app->renderer);
|
||||
}
|
||||
}
|
||||
|
||||
void app_destroy(App *app) {
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
player_destroy(&app->player);
|
||||
channel_list_destroy(&app->channels);
|
||||
destroy_video_texture(app);
|
||||
ui_destroy_fonts(&app->fonts);
|
||||
if (app->renderer) {
|
||||
SDL_DestroyRenderer(app->renderer);
|
||||
}
|
||||
if (app->window) {
|
||||
SDL_DestroyWindow(app->window);
|
||||
}
|
||||
TTF_Quit();
|
||||
SDL_Quit();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue