From f4fa723863a0e5fbf6a4622b77a2bbf7185e1340 Mon Sep 17 00:00:00 2001 From: markmental Date: Fri, 27 Mar 2026 21:45:40 -0400 Subject: [PATCH] Initial Commit --- .gitignore | 2 + Makefile | 38 ++++++ README.md | 54 ++++++++ guide-ui.jpg | Bin 0 -> 95131 bytes src/app.c | 199 ++++++++++++++++++++++++++++ src/app.h | 29 ++++ src/app.o | Bin 0 -> 6072 bytes src/channel.c | 191 +++++++++++++++++++++++++++ src/channel.h | 25 ++++ src/channel.o | Bin 0 -> 5648 bytes src/frame_queue.c | 112 ++++++++++++++++ src/frame_queue.h | 31 +++++ src/frame_queue.o | Bin 0 -> 3520 bytes src/main.c | 17 +++ src/main.o | Bin 0 -> 1824 bytes src/player.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++ src/player.h | 30 +++++ src/player.o | Bin 0 -> 10968 bytes src/theme.h | 26 ++++ src/ui.c | 290 ++++++++++++++++++++++++++++++++++++++++ src/ui.h | 31 +++++ src/ui.o | Bin 0 -> 10680 bytes 22 files changed, 1402 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 guide-ui.jpg create mode 100644 src/app.c create mode 100644 src/app.h create mode 100644 src/app.o create mode 100644 src/channel.c create mode 100644 src/channel.h create mode 100644 src/channel.o create mode 100644 src/frame_queue.c create mode 100644 src/frame_queue.h create mode 100644 src/frame_queue.o create mode 100644 src/main.c create mode 100644 src/main.o create mode 100644 src/player.c create mode 100644 src/player.h create mode 100644 src/player.o create mode 100644 src/theme.h create mode 100644 src/ui.c create mode 100644 src/ui.h create mode 100644 src/ui.o diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bdd7f50 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +passport-c-media-player +media/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cf24809 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +CC ?= cc +CSTD ?= -std=c11 +CFLAGS ?= -O2 -Wall -Wextra -Wpedantic $(CSTD) + +SDL_CFLAGS := $(shell pkg-config --cflags SDL2 SDL2_ttf 2>/dev/null) +SDL_LIBS := $(shell pkg-config --libs SDL2 SDL2_ttf 2>/dev/null) +FFMPEG_CFLAGS := $(shell pkg-config --cflags libavformat libavcodec libswscale libavutil 2>/dev/null) +FFMPEG_LIBS := $(shell pkg-config --libs libavformat libavcodec libswscale libavutil 2>/dev/null) +MULTIARCH_CFLAGS := $(if $(wildcard /usr/include/i386-linux-gnu/SDL2/_real_SDL_config.h),-I/usr/include/i386-linux-gnu,) + +ifeq ($(strip $(SDL_CFLAGS)),) +SDL_CFLAGS := $(shell sdl2-config --cflags 2>/dev/null) $(MULTIARCH_CFLAGS) +SDL_LIBS := $(shell sdl2-config --libs 2>/dev/null) -lSDL2_ttf +endif + +ifeq ($(strip $(FFMPEG_LIBS)),) +FFMPEG_LIBS := -lavformat -lavcodec -lswscale -lavutil +endif + +SRC := $(wildcard src/*.c) +OBJ := $(SRC:.c=.o) +BIN := passport-c-media-player + +CPPFLAGS += -I./src $(SDL_CFLAGS) $(FFMPEG_CFLAGS) +LDLIBS += $(SDL_LIBS) $(FFMPEG_LIBS) -lm + +.PHONY: all run clean + +all: $(BIN) + +$(BIN): $(OBJ) + $(CC) $(OBJ) -o $@ $(LDLIBS) + +run: $(BIN) + ./$(BIN) + +clean: + rm -f $(OBJ) $(BIN) diff --git a/README.md b/README.md new file mode 100644 index 0000000..4332f83 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# Passport-C Media Player + +Passport-C Media Player is a low-dependency SDL2 + FFmpeg prototype that recreates the 2004-era Passport DCT cable guide with live-seeking channels. + +## Features + +- Live-TV epoch clock based on `time(NULL)` +- 200 ms black-screen channel tuning delay +- Fullscreen and guide modes +- 5-row Passport-style guide with a 90-minute timeline +- Background decoder thread with a bounded frame queue +- Automatic channel discovery from `./media` + +## Layout + +- `src/` - application, UI, channel scan, and playback code +- `media/` - channel video files +- `guide-ui.jpg` - visual reference used for proportions and palette + +## Controls + +- `Up` / `Down` - surf channels +- `Tab` - toggle guide +- `Esc` - exit guide or quit the app + +## Build + +Install development packages for SDL2, SDL2_ttf, and FFmpeg headers before building. + +Typical Debian or Ubuntu packages: + +```bash +sudo apt install build-essential libsdl2-dev libsdl2-ttf-dev libavformat-dev libavcodec-dev libswscale-dev libavutil-dev +``` + +Then build and run: + +```bash +make +./passport-c-media-player +``` + +## Media + +The player scans `./media` for supported video files and converts filenames into channel names and current program titles. + +Current sample channels: + +- `media/reading.mp4` +- `media/computers.mp4` + +## Fonts + +The UI tries `BigBlueTermPlus Nerd Font` first, then falls back to common Linux monospace fonts. diff --git a/guide-ui.jpg b/guide-ui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f4401345c6532dbbfedc20ecb3e03cdac75e9d3e GIT binary patch literal 95131 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�plM>13`y-c-_Orxq|>wu<2H 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 +#include +#include + +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(); +} diff --git a/src/app.h b/src/app.h new file mode 100644 index 0000000..214c4f4 --- /dev/null +++ b/src/app.h @@ -0,0 +1,29 @@ +#ifndef APP_H +#define APP_H + +#include + +#include "channel.h" +#include "player.h" +#include "theme.h" +#include "ui.h" + +typedef struct App { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *video_texture; + int texture_width; + int texture_height; + AppMode mode; + int running; + time_t app_start_time; + ChannelList channels; + Player player; + UiFonts fonts; +} App; + +int app_init(App *app); +void app_run(App *app); +void app_destroy(App *app); + +#endif diff --git a/src/app.o b/src/app.o new file mode 100644 index 0000000000000000000000000000000000000000..f4227c4e06a001746a54df2e68f92547830cc44d GIT binary patch literal 6072 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 literal 0 HcmV?d00001 diff --git a/src/channel.c b/src/channel.c new file mode 100644 index 0000000..c4ef3a1 --- /dev/null +++ b/src/channel.c @@ -0,0 +1,191 @@ +#include "channel.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static int has_supported_extension(const char *name) { + const char *dot = strrchr(name, '.'); + if (!dot) { + return 0; + } + + dot++; + return strcasecmp(dot, "mp4") == 0 || + strcasecmp(dot, "mkv") == 0 || + strcasecmp(dot, "mov") == 0 || + strcasecmp(dot, "avi") == 0 || + strcasecmp(dot, "m4v") == 0; +} + +static void trim_extension(char *text) { + char *dot = strrchr(text, '.'); + if (dot) { + *dot = '\0'; + } +} + +static void make_title_case(char *text) { + int new_word = 1; + for (size_t i = 0; text[i] != '\0'; ++i) { + if (text[i] == '-' || text[i] == '_' || text[i] == '.') { + text[i] = ' '; + new_word = 1; + continue; + } + + if (isspace((unsigned char) text[i])) { + new_word = 1; + continue; + } + + text[i] = new_word ? (char) toupper((unsigned char) text[i]) : (char) tolower((unsigned char) text[i]); + new_word = 0; + } +} + +static void derive_channel_name(const char *file_name, char *out, size_t out_size) { + char temp[128]; + snprintf(temp, sizeof(temp), "%s", file_name); + trim_extension(temp); + + if (strstr(temp, "reading") || strstr(temp, "reads")) { + snprintf(out, out_size, "Reading"); + return; + } + + if (strstr(temp, "computer") || strstr(temp, "half-life")) { + snprintf(out, out_size, "Computers"); + return; + } + + make_title_case(temp); + snprintf(out, out_size, "%s", temp); +} + +static void derive_program_title(const char *file_name, char *out, size_t out_size) { + char temp[128]; + snprintf(temp, sizeof(temp), "%s", file_name); + trim_extension(temp); + make_title_case(temp); + snprintf(out, out_size, "%s", temp); +} + +static double probe_duration_seconds(const char *file_path) { + AVFormatContext *format_context = NULL; + double duration = 0.0; + + if (avformat_open_input(&format_context, file_path, NULL, NULL) < 0) { + return 0.0; + } + + if (avformat_find_stream_info(format_context, NULL) >= 0 && format_context->duration > 0) { + duration = (double) format_context->duration / (double) AV_TIME_BASE; + } + + avformat_close_input(&format_context); + return duration; +} + +static int compare_channels(const void *left, const void *right) { + const Channel *a = (const Channel *) left; + const Channel *b = (const Channel *) right; + return strcmp(a->file_name, b->file_name); +} + +int channel_list_load(ChannelList *list, const char *media_dir) { + DIR *directory; + struct dirent *entry; + int capacity = 8; + + if (!list || !media_dir) { + return -1; + } + + list->items = calloc((size_t) capacity, sizeof(Channel)); + list->count = 0; + if (!list->items) { + return -1; + } + + directory = opendir(media_dir); + if (!directory) { + free(list->items); + list->items = NULL; + return -1; + } + + while ((entry = readdir(directory)) != NULL) { + Channel *channel; + + if (entry->d_name[0] == '.' || !has_supported_extension(entry->d_name)) { + continue; + } + + if (list->count == capacity) { + Channel *resized; + capacity *= 2; + resized = realloc(list->items, (size_t) capacity * sizeof(Channel)); + if (!resized) { + closedir(directory); + channel_list_destroy(list); + return -1; + } + list->items = resized; + } + + channel = &list->items[list->count]; + memset(channel, 0, sizeof(*channel)); + channel->number = 50 + list->count; + snprintf(channel->file_name, sizeof(channel->file_name), "%s", entry->d_name); + snprintf(channel->file_path, sizeof(channel->file_path), "%s/%s", media_dir, entry->d_name); + derive_channel_name(entry->d_name, channel->name, sizeof(channel->name)); + derive_program_title(entry->d_name, channel->program_title, sizeof(channel->program_title)); + channel->duration_seconds = probe_duration_seconds(channel->file_path); + list->count += 1; + } + + closedir(directory); + + if (list->count == 0) { + channel_list_destroy(list); + return 0; + } + + qsort(list->items, (size_t) list->count, sizeof(Channel), compare_channels); + for (int i = 0; i < list->count; ++i) { + list->items[i].number = 50 + i; + } + + return list->count; +} + +void channel_list_destroy(ChannelList *list) { + if (!list) { + return; + } + + free(list->items); + list->items = NULL; + list->count = 0; +} + +double channel_live_position(const Channel *channel, time_t app_start_time, time_t now) { + double elapsed; + + if (!channel || channel->duration_seconds <= 0.0) { + return 0.0; + } + + elapsed = difftime(now, app_start_time); + if (elapsed < 0.0) { + elapsed = 0.0; + } + + return fmod(elapsed, channel->duration_seconds); +} diff --git a/src/channel.h b/src/channel.h new file mode 100644 index 0000000..28fb1d4 --- /dev/null +++ b/src/channel.h @@ -0,0 +1,25 @@ +#ifndef CHANNEL_H +#define CHANNEL_H + +#include +#include + +typedef struct Channel { + int number; + char name[64]; + char file_path[PATH_MAX]; + char file_name[128]; + char program_title[128]; + double duration_seconds; +} Channel; + +typedef struct ChannelList { + Channel *items; + int count; +} ChannelList; + +int channel_list_load(ChannelList *list, const char *media_dir); +void channel_list_destroy(ChannelList *list); +double channel_live_position(const Channel *channel, time_t app_start_time, time_t now); + +#endif diff --git a/src/channel.o b/src/channel.o new file mode 100644 index 0000000000000000000000000000000000000000..542bcfa9664d94239bb548f5a0ee1ceed4beec79 GIT binary patch literal 5648 zcmb`KZERE58OM(kr+5tRHHEh63XN&qF094GSxRB8m~Rp%C*ZYJA(TO>YwUY#55LX6 zNkcbSQrm5>j0=_epY-J{4q)5|5*oP8Ds7z&}5$)*GDWjvzd!Fla z;xi{#nx;L9?>Xmp{^vR8KIiS`JN`gVgUv>`*~lhRD{)H5;hSrDpPBU$i7X{_+Dm>SzqQ*&bHB6sy_dk%s#4bTs3*2tnZwUdgr5#`Dpb#Bp1F>sZ?s?>kIcgiZJ-T z;(oGmRL;9$fHZavL*Xr-7>4l$N)fk9`*%uxh`Zju$A1(P-}S zHM-{0k(1c^SdV=yiQH6~#QRfvHL7?-P#AVQ6&q5Epw1U%3@pUL@suqNrT$JJ0ImV5@n z@3+_Y5h%TV3I<}`74+eq`oMXkQVAG;fmvjmihcczbGm7o%;iDkbN4*mwlw z!Vh6IwbiB+cRO%S3sZ9b8hD}MPiSfBrq3#s<2XBJGt?BO4y^1e_LI_<_G9g!Ga7Pb z8yy)%(Z-VlAJdUjM-iXLU8d|-o>GFa*L-9m;|d1%>}w3j;p=np_d$KY;PIcn z4@8>W(#>A9kF8g}rKj(OJy44k#>oswz3$f_t4x0i&gLZEbA3iXx$sm<=B#=E8` z6wJuZ?;{1(*%^6sqNxg(x!o7+ZcW}cs>%Hmn!FtIdF{Q6v#0C>|F|%D z;YqgxJit?vJyXxEq`6bjPwUvOF$fMjvE{2%h{iy-1U$BmntfMWUHL;I-9Zw22T39| zNJ4`#lIR#D_hjL39XvB^3t^fiVK!eR8j5Rc<1tOe_eLAedlb^!)%6uuYqz>57D~Fj z9iDbi+gk6&H7rY3RHelB+~dSHCfY-0p^2EQT&VCdzC>V{^)rt1DcWYU&_r$%A>KMtEn!|Cel&I_d>aTj3~)i@L>!7ss%p^{AQRJzJAR0 z2<*6p{-gyzW5FjZ_@o8DWWhhO;D5K^4z^dJ`akS03;v)5_gU~B3;u`&-wGV#>|{&Y z+@~bIfQ6qIEjS5BL&>BX_k_)ZFO*S(jATh7v{w!4F+C0}lvRl*(6t^P zUVOCUX+9$w4HJDCiV|px=B$1e=>9K@Lv_vXmuD2ex>hPSxe_h~1$F!XS$Fq_1BLZI` z@V^NBR)IIcIzU7Jcvf*gxW3WwM8_q?`FcT*_XX$M1%A80HNg*_VqBjT^j{D-e#D|- zzl-3<^&=MggMuEH1uYU?$9M5X=Yq7enMEyeo z$2*XZXN$n^6nK(x>_!s!w*-BQz+Vx#xITX%aF?KeN8qakemhPe7$$eYkB_s9aU72< z@GXK~jPnzM9`9f7CupHRB5*NozYzG{f}gVjcL{t_;G+IB3%-io8(1yspAq=Ig8%mg z{zZXfOwiB|eBaN#uM6^M7&rWJDQnFeYJ4`ONUr{R~_g5@^m}Y^Smg1?Z1p4ey?MDaj&2s-u`1O z2*$_Fkp`KC=Kl@clwd>E#GHS;2YGuw{|ohvO*pR2p}63{ Z_`O{%&5srOT&R6Bo6rH?kfrsp{x`Q5y~zLo literal 0 HcmV?d00001 diff --git a/src/frame_queue.c b/src/frame_queue.c new file mode 100644 index 0000000..4122e4a --- /dev/null +++ b/src/frame_queue.c @@ -0,0 +1,112 @@ +#include "frame_queue.h" + +#include +#include + +void frame_data_free(FrameData *frame) { + if (!frame) { + return; + } + + free(frame->pixels); + memset(frame, 0, sizeof(*frame)); +} + +int frame_queue_init(FrameQueue *queue) { + if (!queue) { + return -1; + } + + memset(queue, 0, sizeof(*queue)); + queue->mutex = SDL_CreateMutex(); + queue->cond = SDL_CreateCond(); + + return (queue->mutex && queue->cond) ? 0 : -1; +} + +void frame_queue_clear(FrameQueue *queue) { + if (!queue || !queue->mutex) { + return; + } + + SDL_LockMutex(queue->mutex); + while (queue->count > 0) { + frame_data_free(&queue->frames[queue->head]); + queue->head = (queue->head + 1) % FRAME_QUEUE_CAPACITY; + queue->count -= 1; + } + queue->head = 0; + SDL_UnlockMutex(queue->mutex); +} + +void frame_queue_destroy(FrameQueue *queue) { + if (!queue) { + return; + } + + frame_queue_clear(queue); + if (queue->cond) { + SDL_DestroyCond(queue->cond); + } + if (queue->mutex) { + SDL_DestroyMutex(queue->mutex); + } + memset(queue, 0, sizeof(*queue)); +} + +int frame_queue_push(FrameQueue *queue, FrameData *frame) { + int tail; + + if (!queue || !frame || !queue->mutex) { + return -1; + } + + SDL_LockMutex(queue->mutex); + + if (queue->count == FRAME_QUEUE_CAPACITY) { + frame_data_free(&queue->frames[queue->head]); + queue->head = (queue->head + 1) % FRAME_QUEUE_CAPACITY; + queue->count -= 1; + } + + tail = (queue->head + queue->count) % FRAME_QUEUE_CAPACITY; + queue->frames[tail] = *frame; + memset(frame, 0, sizeof(*frame)); + queue->count += 1; + SDL_CondSignal(queue->cond); + SDL_UnlockMutex(queue->mutex); + return 0; +} + +int frame_queue_pop_latest(FrameQueue *queue, FrameData *out) { + int latest_index; + + if (!queue || !out || !queue->mutex) { + return 0; + } + + SDL_LockMutex(queue->mutex); + if (queue->count == 0) { + SDL_UnlockMutex(queue->mutex); + return 0; + } + + latest_index = (queue->head + queue->count - 1) % FRAME_QUEUE_CAPACITY; + *out = queue->frames[latest_index]; + memset(&queue->frames[latest_index], 0, sizeof(queue->frames[latest_index])); + + while (queue->count > 0) { + if (queue->head == latest_index) { + queue->head = 0; + queue->count = 0; + break; + } + + frame_data_free(&queue->frames[queue->head]); + queue->head = (queue->head + 1) % FRAME_QUEUE_CAPACITY; + queue->count -= 1; + } + + SDL_UnlockMutex(queue->mutex); + return 1; +} diff --git a/src/frame_queue.h b/src/frame_queue.h new file mode 100644 index 0000000..d028bc8 --- /dev/null +++ b/src/frame_queue.h @@ -0,0 +1,31 @@ +#ifndef FRAME_QUEUE_H +#define FRAME_QUEUE_H + +#include + +#define FRAME_QUEUE_CAPACITY 4 + +typedef struct FrameData { + unsigned char *pixels; + int width; + int height; + int stride; + double pts_seconds; +} FrameData; + +typedef struct FrameQueue { + FrameData frames[FRAME_QUEUE_CAPACITY]; + int head; + int count; + SDL_mutex *mutex; + SDL_cond *cond; +} FrameQueue; + +int frame_queue_init(FrameQueue *queue); +void frame_queue_destroy(FrameQueue *queue); +void frame_queue_clear(FrameQueue *queue); +int frame_queue_push(FrameQueue *queue, FrameData *frame); +int frame_queue_pop_latest(FrameQueue *queue, FrameData *out); +void frame_data_free(FrameData *frame); + +#endif diff --git a/src/frame_queue.o b/src/frame_queue.o new file mode 100644 index 0000000000000000000000000000000000000000..db9520678bf84209ba07b218bb79d132d6774ba6 GIT binary patch literal 3520 zcmbtWU2GIp6uz_D%1Z0Z*7(o}(rwbHO<+UC2SB4c?m};&Vz88-ETk^WtTeP;*qtUI z39Xr3a2%G@07;F(7o!i#12INP(75Xe^?`@RpQ!P{CTJ|yL`@9=0qZ$;?(JUIX=3yw zopbMZe(yKu&UR#7_xgaM5FrYAf>d_`C8WH#x{k4Bj5Lx4LW^_ek{)W`q|TGmh-b84 z%UV-VYl?@HZf4BQWTIM2fkkL7G3K9P{-u#nN10A^UPl|Xzoiq$USe*rvwpfx+i$#B z83&+pH8@M(VY#Vop^LY+E--iP^e41f2Fn;&lG^FA_I|l_(wbJ>^K&3R^|itW;Mz;= z+db6!B}AQ%F%cX@E1VG7og%heEFanBoEe2xMx24BzoV5a^;DUm&SR_*>A+4AeM{RF z`(4sVP$p+}EnC<2YUSr;%A_?FY@ej#v@!*x zPHRmBjfu9f))WgPwYt_+*9H%OfFnGe#pqM``50|%-BC{N(sv?N$Q$M>?W_l47kEuh z2^+J@iquDG^PJ5ZwOQ9!H^T&Z`PeYcyl#DV$3$hu*w{RzARj=6JN#TRl3~W_H33nxI z&msmAg#O4zHGCZN9u4Yh#HtINz|3m+DK*sDfPK1`E@LlK@Q1Q$K1Q#`+=LjY0Wq{; zliD0-%XJXx#rQojO&$4t&d(O~`J!v!c&~)F^1%B+hkcT?aDO~63gZ_v?*05@3*gTH zj&;w0MyYs;@#>c+3wA$z1aQnViU$Wtd5W9_?dSi-0{DA?W1io59`+6aySRY=m)xJQ zPbhzXfRRitHE8r57&eBDXqxZ#q|8)bCTAG3wXc7u-y}VW?!I`=NSVgd!=`ai+Q+j) zd+zX04;ZN&bLh^d_f_3{hX&^NQuV$)M&8V253z`Zw`Mu9B;R{Ue-`Mq8fP`;=C z`JvRn9Zl@d?(Z9bZu2G{mXLcq1v7_pN60Pwu?6Xu@Vg{@Si%=c_!km>w}k&C;d1_$ z`FlbvB>BH4;f)f0R>HAo(dPpJ*nnUjx$a>J$2%hYk4ZTGD>tDp2r4;$>jL;z>0GjZ1e1VZTf8;4f1Ew5_)5OtUW1?G`%^WzxM#vH@{4=(Lyf<< zA0(PTG-#%FgEn)X-YZr)V;~iU;WtSXZwiU-&gV%qogExBh5#GNnntv9Q}2qrnM&^? zQRZ&!g$o5YjhFl1DgqghN}N?$VtliT^Dk_*-_{Bem1wnRrYW`Up|2MrHublt@ literal 0 HcmV?d00001 diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..9748f4e --- /dev/null +++ b/src/main.c @@ -0,0 +1,17 @@ +#include "app.h" + +#include + +int main(void) { + App app; + + if (app_init(&app) != 0) { + fprintf(stderr, "Failed to start Passport-C Media Player.\n"); + app_destroy(&app); + return 1; + } + + app_run(&app); + app_destroy(&app); + return 0; +} diff --git a/src/main.o b/src/main.o new file mode 100644 index 0000000000000000000000000000000000000000..ce1de1b7791b531afacfe174f8bff497815a6eb6 GIT binary patch literal 1824 zcmbW2&1w`u5XWniXktu;RXhYDGUCBROq&Fes3^0nX7><7RDy^|=wv%)aKD)8XyQeJ zCYnP|r`KnuyK*^llB27% zYdK2vrh8Wpj2e(fgETF}s;c<9;m2A=+Mkng+-yX8tmxlRl~DR~Rk^Mr(Qm`&Z;A-fF)7B!CN7RzmFO5ES#nQqQEn}t8y@KGd(DZ?GCOWoh!!vxy!?x< zf;aT6yX1ZCQT^Uf(aRUSzQSSa)qX-vJ@j|G-D)=-Xu*Ak^t5p7_GrrA)MOY@zQvnp zm{~i1sslgQfnVsrsV2j^SRye~95*`2W^*B|huSF7YTe8g73-+6PO+}2D5B-ZQK%KC z^L%qUnpSI?L`7;zVlj?ML=715oDfrNs;U%lV#0T1wMk;B zQLCvsN7WlziPG%+7%we7w7zO(VL6gDb8tHa>`%e@q9<{-X$jIsN{4S+PO<@(y8dQ4 zFwfRUHvTlb;5+R%9`_PCCwZhLu*R7*WIef0Neq?(9*EEGzsU^Z?p0#7-XZiGdL(cT zc3!c~@z&b-RX|_6_YYY<%QN0TZf!Sxv5N12o!$Al`3`fZr(J)ijg+4Ct=jlKz0B;7 zjVY&Mp}P7Ve!xn*{palmb^FBralc%= +#include +#include +#include +#include +#include +#include +#include + +typedef struct DecoderThreadArgs { + Player *player; + const Channel *channel; +} DecoderThreadArgs; + +static void player_set_error(Player *player, const char *message) { + if (!player || !player->error_mutex) { + return; + } + + SDL_LockMutex(player->error_mutex); + snprintf(player->last_error, sizeof(player->last_error), "%s", message ? message : "Unknown playback error"); + SDL_UnlockMutex(player->error_mutex); +} + +static int should_stop(Player *player) { + return player ? SDL_AtomicGet(&player->stop_requested) : 1; +} + +static int decode_thread_main(void *userdata) { + DecoderThreadArgs *args = (DecoderThreadArgs *) userdata; + Player *player = args->player; + const Channel *channel = args->channel; + AVFormatContext *format_context = NULL; + AVCodecContext *codec_context = NULL; + AVPacket *packet = NULL; + AVFrame *decoded_frame = NULL; + struct SwsContext *sws_context = NULL; + const AVCodec *codec = NULL; + int video_stream_index = -1; + int rc = -1; + int rgb_stride = 0; + double seek_seconds = 0.0; + AVRational time_base; + Uint64 wall_base_ms = 0; + int first_frame = 1; + + free(args); + + if (avformat_open_input(&format_context, channel->file_path, NULL, NULL) < 0) { + player_set_error(player, "Unable to open media file"); + return -1; + } + + if (avformat_find_stream_info(format_context, NULL) < 0) { + player_set_error(player, "Unable to read stream metadata"); + goto cleanup; + } + + for (unsigned int i = 0; i < format_context->nb_streams; ++i) { + if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + video_stream_index = (int) i; + break; + } + } + + if (video_stream_index < 0) { + player_set_error(player, "No video stream found"); + goto cleanup; + } + + codec = avcodec_find_decoder(format_context->streams[video_stream_index]->codecpar->codec_id); + if (!codec) { + player_set_error(player, "Unsupported video codec"); + goto cleanup; + } + + codec_context = avcodec_alloc_context3(codec); + if (!codec_context) { + player_set_error(player, "Unable to allocate codec context"); + goto cleanup; + } + + if (avcodec_parameters_to_context(codec_context, format_context->streams[video_stream_index]->codecpar) < 0 || + avcodec_open2(codec_context, codec, NULL) < 0) { + player_set_error(player, "Unable to initialize decoder"); + goto cleanup; + } + + decoded_frame = av_frame_alloc(); + packet = av_packet_alloc(); + if (!decoded_frame || !packet) { + player_set_error(player, "Unable to allocate FFmpeg frame buffers"); + goto cleanup; + } + + rgb_stride = codec_context->width * 4; + time_base = format_context->streams[video_stream_index]->time_base; + sws_context = sws_getContext(codec_context->width, + codec_context->height, + codec_context->pix_fmt, + codec_context->width, + codec_context->height, + AV_PIX_FMT_RGBA, + SWS_BILINEAR, + NULL, + NULL, + NULL); + if (!sws_context) { + player_set_error(player, "Unable to initialize scaler"); + goto cleanup; + } + + seek_seconds = channel_live_position(channel, player->app_start_time, time(NULL)); + if (channel->duration_seconds > 0.0) { + int64_t seek_target = (int64_t) (seek_seconds / av_q2d(time_base)); + avformat_seek_file(format_context, video_stream_index, INT64_MIN, seek_target, INT64_MAX, 0); + avcodec_flush_buffers(codec_context); + } + + while (!should_stop(player)) { + if (av_read_frame(format_context, packet) < 0) { + if (channel->duration_seconds > 0.0) { + seek_seconds = 0.0; + wall_base_ms = SDL_GetTicks64(); + avformat_seek_file(format_context, video_stream_index, INT64_MIN, 0, INT64_MAX, 0); + avcodec_flush_buffers(codec_context); + continue; + } + break; + } + + if (packet->stream_index != video_stream_index) { + av_packet_unref(packet); + continue; + } + + if (avcodec_send_packet(codec_context, packet) < 0) { + av_packet_unref(packet); + continue; + } + av_packet_unref(packet); + + while (!should_stop(player)) { + double frame_seconds; + int delay_ms; + int receive = avcodec_receive_frame(codec_context, decoded_frame); + if (receive == AVERROR(EAGAIN) || receive == AVERROR_EOF) { + break; + } + if (receive < 0) { + player_set_error(player, "Video decode failed"); + goto cleanup; + } + + frame_seconds = decoded_frame->best_effort_timestamp == AV_NOPTS_VALUE + ? seek_seconds + : decoded_frame->best_effort_timestamp * av_q2d(time_base); + + if (first_frame) { + wall_base_ms = SDL_GetTicks64(); + first_frame = 0; + } + + delay_ms = (int) (((frame_seconds - seek_seconds) * 1000.0) - (double) (SDL_GetTicks64() - wall_base_ms)); + if (delay_ms > 1 && delay_ms < 250) { + SDL_Delay((Uint32) delay_ms); + } + + { + FrameData frame = {0}; + uint8_t *dest_data[4] = {0}; + int dest_linesize[4] = {0}; + + frame.width = codec_context->width; + frame.height = codec_context->height; + frame.stride = rgb_stride; + frame.pts_seconds = frame_seconds; + frame.pixels = malloc((size_t) frame.stride * (size_t) frame.height); + if (!frame.pixels) { + player_set_error(player, "Unable to allocate frame buffer"); + goto cleanup; + } + + dest_data[0] = frame.pixels; + dest_linesize[0] = frame.stride; + sws_scale(sws_context, + (const uint8_t *const *) decoded_frame->data, + decoded_frame->linesize, + 0, + codec_context->height, + dest_data, + dest_linesize); + frame_queue_push(&player->frame_queue, &frame); + } + } + } + + rc = 0; + +cleanup: + if (packet) { + av_packet_free(&packet); + } + if (decoded_frame) { + av_frame_free(&decoded_frame); + } + if (codec_context) { + avcodec_free_context(&codec_context); + } + if (format_context) { + avformat_close_input(&format_context); + } + if (sws_context) { + sws_freeContext(sws_context); + } + return rc; +} + +static void player_stop_thread(Player *player) { + if (!player || !player->thread) { + return; + } + + SDL_AtomicSet(&player->stop_requested, 1); + SDL_WaitThread(player->thread, NULL); + player->thread = NULL; +} + +int player_init(Player *player, const ChannelList *channels, time_t app_start_time) { + if (!player || !channels) { + return -1; + } + + memset(player, 0, sizeof(*player)); + player->channels = channels; + player->current_index = -1; + player->app_start_time = app_start_time; + player->error_mutex = SDL_CreateMutex(); + if (!player->error_mutex) { + return -1; + } + + if (frame_queue_init(&player->frame_queue) != 0) { + SDL_DestroyMutex(player->error_mutex); + memset(player, 0, sizeof(*player)); + return -1; + } + + return 0; +} + +void player_destroy(Player *player) { + if (!player) { + return; + } + + player_stop_thread(player); + frame_queue_destroy(&player->frame_queue); + if (player->error_mutex) { + SDL_DestroyMutex(player->error_mutex); + } + memset(player, 0, sizeof(*player)); +} + +int player_tune(Player *player, int channel_index) { + DecoderThreadArgs *args; + + if (!player || !player->channels || channel_index < 0 || channel_index >= player->channels->count) { + return -1; + } + + player_stop_thread(player); + frame_queue_clear(&player->frame_queue); + SDL_AtomicSet(&player->stop_requested, 0); + player->current_index = channel_index; + player->tuning_blackout_until = SDL_GetTicks() + 200; + player_set_error(player, ""); + + args = malloc(sizeof(*args)); + if (!args) { + player_set_error(player, "Unable to allocate thread args"); + return -1; + } + + args->player = player; + args->channel = &player->channels->items[channel_index]; + player->thread = SDL_CreateThread(decode_thread_main, "decoder", args); + if (!player->thread) { + free(args); + player_set_error(player, "Unable to start decoder thread"); + return -1; + } + + return 0; +} + +int player_consume_latest_frame(Player *player, FrameData *out) { + if (!player || !out) { + return 0; + } + + return frame_queue_pop_latest(&player->frame_queue, out); +} + +double player_live_position(const Player *player, time_t now) { + if (!player || !player->channels || player->current_index < 0 || player->current_index >= player->channels->count) { + return 0.0; + } + + return channel_live_position(&player->channels->items[player->current_index], player->app_start_time, now); +} + +int player_is_in_blackout(const Player *player) { + return player && SDL_GetTicks() < player->tuning_blackout_until; +} + +void player_get_error(Player *player, char *buffer, size_t buffer_size) { + if (!player || !buffer || buffer_size == 0) { + return; + } + + SDL_LockMutex(player->error_mutex); + snprintf(buffer, buffer_size, "%s", player->last_error); + SDL_UnlockMutex(player->error_mutex); +} diff --git a/src/player.h b/src/player.h new file mode 100644 index 0000000..b7fd911 --- /dev/null +++ b/src/player.h @@ -0,0 +1,30 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include + +#include "channel.h" +#include "frame_queue.h" + +typedef struct Player { + FrameQueue frame_queue; + SDL_Thread *thread; + SDL_atomic_t stop_requested; + const ChannelList *channels; + int current_index; + time_t app_start_time; + Uint32 tuning_blackout_until; + SDL_mutex *error_mutex; + char last_error[256]; +} Player; + +int player_init(Player *player, const ChannelList *channels, time_t app_start_time); +void player_destroy(Player *player); +int player_tune(Player *player, int channel_index); +int player_consume_latest_frame(Player *player, FrameData *out); +double player_live_position(const Player *player, time_t now); +int player_is_in_blackout(const Player *player); +void player_get_error(Player *player, char *buffer, size_t buffer_size); + +#endif diff --git a/src/player.o b/src/player.o new file mode 100644 index 0000000000000000000000000000000000000000..9ce72460399a342fab4e91e75c1bc880cd045fc0 GIT binary patch literal 10968 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 + +typedef enum AppMode { + MODE_FULLSCREEN = 0, + MODE_GUIDE = 1 +} AppMode; + +static const SDL_Color COLOR_DEEP_BLUE = {0x00, 0x33, 0x99, 0xff}; +static const SDL_Color COLOR_HIGHLIGHT_YELLOW = {0xff, 0xd7, 0x00, 0xff}; +static const SDL_Color COLOR_HINT_RED = {0xcc, 0x00, 0x00, 0xff}; +static const SDL_Color COLOR_NAVY_DARK = {0x05, 0x16, 0x46, 0xff}; +static const SDL_Color COLOR_SLATE = {0x52, 0x67, 0x96, 0xff}; +static const SDL_Color COLOR_PALE_BLUE = {0xcc, 0xd8, 0xf3, 0xff}; +static const SDL_Color COLOR_TEXT_LIGHT = {0xf5, 0xf7, 0xfa, 0xff}; +static const SDL_Color COLOR_TEXT_DARK = {0x0b, 0x11, 0x1d, 0xff}; +static const SDL_Color COLOR_BLACK = {0x00, 0x00, 0x00, 0xff}; + +#define WINDOW_WIDTH 1280 +#define WINDOW_HEIGHT 720 +#define GUIDE_VISIBLE_ROWS 5 +#define TIMELINE_VISIBLE_SECONDS (90.0 * 60.0) + +#endif diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..654be97 --- /dev/null +++ b/src/ui.c @@ -0,0 +1,290 @@ +#include "ui.h" + +#include +#include + +static const char *FONT_CANDIDATES[] = { + "BigBlueTermPlus Nerd Font Mono.ttf", + "BigBlueTermPlusNerdFontMono-Regular.ttf", + "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/TTF/DejaVuSansMono.ttf", + "/usr/share/fonts/truetype/liberation2/LiberationMono-Regular.ttf" +}; + +static void fill_rect(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color color); + +static void set_draw_color(SDL_Renderer *renderer, SDL_Color color) { + SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); +} + +static SDL_Texture *text_to_texture(SDL_Renderer *renderer, TTF_Font *font, const char *text, SDL_Color color, int *width, int *height) { + SDL_Surface *surface; + SDL_Texture *texture; + + if (!font || !text || text[0] == '\0') { + return NULL; + } + + surface = TTF_RenderUTF8_Blended(font, text, color); + if (!surface) { + return NULL; + } + + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (width) { + *width = surface->w; + } + if (height) { + *height = surface->h; + } + SDL_FreeSurface(surface); + return texture; +} + +static void draw_text(SDL_Renderer *renderer, TTF_Font *font, const char *text, int x, int y, SDL_Color color) { + SDL_Texture *texture; + SDL_Rect dst; + int width = 0; + int height = 0; + + texture = text_to_texture(renderer, font, text, color, &width, &height); + if (!texture) { + return; + } + + dst.x = x; + dst.y = y; + dst.w = width; + dst.h = height; + SDL_RenderCopy(renderer, texture, NULL, &dst); + SDL_DestroyTexture(texture); +} + +static void fill_rect(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color color) { + set_draw_color(renderer, color); + SDL_RenderFillRect(renderer, rect); +} + +static void stroke_rect(SDL_Renderer *renderer, const SDL_Rect *rect, SDL_Color color) { + set_draw_color(renderer, color); + SDL_RenderDrawRect(renderer, rect); +} + +static SDL_Rect fit_rect(int outer_x, int outer_y, int outer_w, int outer_h, int inner_w, int inner_h) { + SDL_Rect dst = {outer_x, outer_y, outer_w, outer_h}; + double scale; + + if (inner_w <= 0 || inner_h <= 0) { + return dst; + } + + scale = SDL_min((double) outer_w / (double) inner_w, (double) outer_h / (double) inner_h); + dst.w = (int) (inner_w * scale); + dst.h = (int) (inner_h * scale); + dst.x = outer_x + (outer_w - dst.w) / 2; + dst.y = outer_y + (outer_h - dst.h) / 2; + return dst; +} + +static void draw_video(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, int texture_height, SDL_Rect destination) { + if (!video_texture) { + fill_rect(renderer, &destination, COLOR_BLACK); + return; + } + + { + SDL_Rect fitted = fit_rect(destination.x, destination.y, destination.w, destination.h, texture_width, texture_height); + fill_rect(renderer, &destination, COLOR_BLACK); + SDL_RenderCopy(renderer, video_texture, NULL, &fitted); + } +} + +static void format_clock_label(char *buffer, size_t buffer_size, time_t now, int minute_offset) { + struct tm local_time; + time_t slot = now + minute_offset * 60; + localtime_r(&slot, &local_time); + strftime(buffer, buffer_size, "%I:%M %p", &local_time); +} + +static void draw_timeline_header(SDL_Renderer *renderer, const UiFonts *fonts, SDL_Rect rect, time_t now) { + char label[32]; + int segments = 4; + + draw_text(renderer, fonts->medium, "FRI 6/30", rect.x + 12, rect.y + 8, COLOR_TEXT_DARK); + + for (int i = 0; i < segments; ++i) { + int x = rect.x + (rect.w * i) / segments; + format_clock_label(label, sizeof(label), now, (int) ((TIMELINE_VISIBLE_SECONDS / 60.0 / segments) * i)); + draw_text(renderer, fonts->small, label, x + 6, rect.y + 10, COLOR_TEXT_DARK); + set_draw_color(renderer, COLOR_SLATE); + SDL_RenderDrawLine(renderer, x, rect.y + rect.h - 4, x, rect.y + rect.h + 5 * 76); + } +} + +static void draw_footer_legend(SDL_Renderer *renderer, const UiFonts *fonts, int window_width, int window_height) { + SDL_Rect footer = {0, window_height - 54, window_width, 54}; + SDL_Rect chip = {window_width / 2 - 170, window_height - 40, 24, 24}; + + fill_rect(renderer, &footer, COLOR_PALE_BLUE); + set_draw_color(renderer, COLOR_SLATE); + SDL_RenderDrawLine(renderer, footer.x, footer.y, footer.x + footer.w, footer.y); + + fill_rect(renderer, &chip, COLOR_HIGHLIGHT_YELLOW); + draw_text(renderer, fonts->medium, "A", chip.x + 7, chip.y + 2, COLOR_TEXT_DARK); + draw_text(renderer, fonts->medium, "Time", chip.x + 34, chip.y + 1, COLOR_TEXT_DARK); + + chip.x += 132; + fill_rect(renderer, &chip, COLOR_DEEP_BLUE); + draw_text(renderer, fonts->medium, "B", chip.x + 7, chip.y + 2, COLOR_TEXT_LIGHT); + draw_text(renderer, fonts->medium, "Theme", chip.x + 34, chip.y + 1, COLOR_TEXT_DARK); + + chip.x += 136; + fill_rect(renderer, &chip, COLOR_HINT_RED); + draw_text(renderer, fonts->medium, "C", chip.x + 7, chip.y + 2, COLOR_TEXT_LIGHT); + draw_text(renderer, fonts->medium, "Title", chip.x + 34, chip.y + 1, COLOR_TEXT_DARK); +} + +void ui_render_no_media(SDL_Renderer *renderer, const UiFonts *fonts) { + SDL_Rect full = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + fill_rect(renderer, &full, COLOR_NAVY_DARK); + draw_text(renderer, fonts->large, "Passport-C Media Player", 58, 80, COLOR_TEXT_LIGHT); + draw_text(renderer, fonts->medium, "No channels found in ./media", 58, 136, COLOR_HIGHLIGHT_YELLOW); + draw_text(renderer, fonts->small, "Add MP4 or MKV files to ./media and relaunch.", 58, 176, COLOR_PALE_BLUE); +} + +void ui_render_fullscreen(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, int texture_height) { + SDL_Rect window = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + fill_rect(renderer, &window, COLOR_BLACK); + draw_video(renderer, video_texture, texture_width, texture_height, window); +} + +void ui_render_guide(SDL_Renderer *renderer, + SDL_Texture *video_texture, + int texture_width, + int texture_height, + const UiFonts *fonts, + const ChannelList *channels, + int active_channel, + time_t app_start_time, + time_t now) { + SDL_Rect full = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + SDL_Rect header_card = {0, 0, 390, 168}; + SDL_Rect preview = {820, 0, 460, 210}; + SDL_Rect header_row = {0, 210, WINDOW_WIDTH, 42}; + SDL_Rect grid = {0, 252, WINDOW_WIDTH, WINDOW_HEIGHT - 306}; + int row_height = grid.h / GUIDE_VISIBLE_ROWS; + int sidebar_width = 240; + int timeline_x = sidebar_width + 8; + int timeline_w = WINDOW_WIDTH - timeline_x - 12; + int start_index = active_channel - 2; + char detail[256]; + + fill_rect(renderer, &full, COLOR_NAVY_DARK); + fill_rect(renderer, &header_card, COLOR_PALE_BLUE); + fill_rect(renderer, &preview, COLOR_BLACK); + draw_video(renderer, video_texture, texture_width, texture_height, preview); + fill_rect(renderer, &header_row, COLOR_SLATE); + + if (channels && channels->count > 0 && active_channel >= 0 && active_channel < channels->count) { + const Channel *current = &channels->items[active_channel]; + snprintf(detail, sizeof(detail), "%.0f min - %s", current->duration_seconds / 60.0, current->file_name); + fill_rect(renderer, &(SDL_Rect){0, 0, 390, 38}, COLOR_HIGHLIGHT_YELLOW); + draw_text(renderer, fonts->large, current->name, 26, 44, COLOR_TEXT_DARK); + draw_text(renderer, fonts->medium, current->program_title, 20, 92, COLOR_TEXT_DARK); + draw_text(renderer, fonts->small, detail, 20, 124, COLOR_TEXT_DARK); + draw_text(renderer, fonts->medium, "Nick * 56", preview.x + preview.w - 126, preview.y + preview.h - 34, COLOR_TEXT_LIGHT); + } + + draw_timeline_header(renderer, fonts, header_row, now); + + if (start_index < 0) { + start_index = 0; + } + if (channels && start_index + GUIDE_VISIBLE_ROWS > channels->count) { + start_index = SDL_max(0, channels->count - GUIDE_VISIBLE_ROWS); + } + + for (int row = 0; row < GUIDE_VISIBLE_ROWS; ++row) { + int channel_index = start_index + row; + SDL_Rect row_rect = {0, grid.y + row * row_height, WINDOW_WIDTH, row_height}; + SDL_Rect sidebar = {0, row_rect.y, sidebar_width, row_height}; + SDL_Rect timeline_rect = {timeline_x, row_rect.y + 6, timeline_w, row_height - 12}; + SDL_Rect clip = timeline_rect; + int is_selected = channel_index == active_channel; + + fill_rect(renderer, &row_rect, is_selected ? COLOR_DEEP_BLUE : COLOR_NAVY_DARK); + fill_rect(renderer, &sidebar, is_selected ? COLOR_DEEP_BLUE : COLOR_SLATE); + set_draw_color(renderer, COLOR_PALE_BLUE); + SDL_RenderDrawLine(renderer, row_rect.x, row_rect.y, row_rect.x + row_rect.w, row_rect.y); + + if (!channels || channel_index >= channels->count) { + continue; + } + + { + const Channel *channel = &channels->items[channel_index]; + char number[16]; + double live_position = channel_live_position(channel, app_start_time, now); + double pixels_per_second = timeline_w / TIMELINE_VISIBLE_SECONDS; + int block_x = timeline_x - (int) (live_position * pixels_per_second); + int block_w = (int) (channel->duration_seconds * pixels_per_second); + SDL_Rect block = {block_x, timeline_rect.y + 4, SDL_max(block_w, 48), timeline_rect.h - 8}; + + snprintf(number, sizeof(number), "%d", channel->number); + draw_text(renderer, fonts->medium, channel->name, 20, row_rect.y + 12, COLOR_TEXT_LIGHT); + draw_text(renderer, fonts->medium, number, 176, row_rect.y + 12, COLOR_TEXT_LIGHT); + draw_text(renderer, fonts->small, channel->file_name, 20, row_rect.y + 38, COLOR_PALE_BLUE); + + fill_rect(renderer, &timeline_rect, COLOR_NAVY_DARK); + SDL_RenderSetClipRect(renderer, &clip); + fill_rect(renderer, &block, is_selected ? COLOR_HIGHLIGHT_YELLOW : COLOR_DEEP_BLUE); + stroke_rect(renderer, &block, COLOR_PALE_BLUE); + draw_text(renderer, + is_selected ? fonts->medium : fonts->small, + channel->program_title, + block.x + 10, + block.y + 10, + is_selected ? COLOR_TEXT_DARK : COLOR_TEXT_LIGHT); + SDL_RenderSetClipRect(renderer, NULL); + stroke_rect(renderer, &timeline_rect, COLOR_SLATE); + } + } + + draw_footer_legend(renderer, fonts, WINDOW_WIDTH, WINDOW_HEIGHT); +} + +int ui_load_fonts(UiFonts *fonts) { + if (!fonts) { + return -1; + } + + memset(fonts, 0, sizeof(*fonts)); + for (size_t i = 0; i < sizeof(FONT_CANDIDATES) / sizeof(FONT_CANDIDATES[0]); ++i) { + fonts->small = TTF_OpenFont(FONT_CANDIDATES[i], 18); + fonts->medium = TTF_OpenFont(FONT_CANDIDATES[i], 24); + fonts->large = TTF_OpenFont(FONT_CANDIDATES[i], 32); + if (fonts->small && fonts->medium && fonts->large) { + return 0; + } + ui_destroy_fonts(fonts); + } + + return -1; +} + +void ui_destroy_fonts(UiFonts *fonts) { + if (!fonts) { + return; + } + + if (fonts->small) { + TTF_CloseFont(fonts->small); + } + if (fonts->medium) { + TTF_CloseFont(fonts->medium); + } + if (fonts->large) { + TTF_CloseFont(fonts->large); + } + memset(fonts, 0, sizeof(*fonts)); +} diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 0000000..c251352 --- /dev/null +++ b/src/ui.h @@ -0,0 +1,31 @@ +#ifndef UI_H +#define UI_H + +#include +#include +#include + +#include "channel.h" +#include "theme.h" + +typedef struct UiFonts { + TTF_Font *small; + TTF_Font *medium; + TTF_Font *large; +} UiFonts; + +void ui_render_fullscreen(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, int texture_height); +void ui_render_guide(SDL_Renderer *renderer, + SDL_Texture *video_texture, + int texture_width, + int texture_height, + const UiFonts *fonts, + const ChannelList *channels, + int active_channel, + time_t app_start_time, + time_t now); +void ui_render_no_media(SDL_Renderer *renderer, const UiFonts *fonts); +int ui_load_fonts(UiFonts *fonts); +void ui_destroy_fonts(UiFonts *fonts); + +#endif diff --git a/src/ui.o b/src/ui.o new file mode 100644 index 0000000000000000000000000000000000000000..de0ec258ca607caf47331b41c16bf5873abfd092 GIT binary patch literal 10680 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