Skip to content
This repository was archived by the owner on Dec 19, 2024. It is now read-only.

Commit

Permalink
Update dependencies; remove cache parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
zuranthus committed Dec 4, 2024
1 parent c14f651 commit 21ff3f9
Showing 5 changed files with 96 additions and 107 deletions.
30 changes: 17 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
cmake_minimum_required(VERSION 3.14)
project(live-paper VERSION 0.0.0)

if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24.0)
cmake_policy(SET CMP0135 NEW)
endif()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

include(FetchContent)

##### FFmpeg
# FFmpeg
if(NOT MSVC)
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
find_package(FFmpeg 6.0 REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
else()
FetchContent_Declare(
FFmpeg
URL https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-4.3.2-full_build-shared.7z
)
FetchContent_GetProperties(FFmpeg)
if(NOT ffmpeg_POPULATED)
FetchContent_Populate(FFmpeg)
FetchContent_MakeAvailable(FFmpeg)
add_library(FFmpeg::FFmpeg INTERFACE IMPORTED)
set_target_properties(FFmpeg::FFmpeg PROPERTIES
INTERFACE_LINK_DIRECTORIES "${ffmpeg_SOURCE_DIR}/lib"
@@ -28,7 +32,7 @@ else()
endif()


##### SDL2
# SDL2
if(NOT MSVC)
find_package(SDL2 REQUIRED)
if (NOT TARGET SDL2::SDL2)
@@ -45,7 +49,7 @@ else()
)
FetchContent_GetProperties(SDL2)
if(NOT sdl2_POPULATED)
FetchContent_Populate(SDL2)
FetchContent_MakeAvailable(SDL2)
add_library(SDL2::SDL2 SHARED IMPORTED)
set_target_properties(SDL2::SDL2 PROPERTIES
IMPORTED_LOCATION "${sdl2_SOURCE_DIR}/lib/x64/SDL2.dll"
@@ -60,7 +64,7 @@ else()
endif()


##### tray (on windows only)
# tray (on windows only)
if(WIN32)
FetchContent_Declare(
tray
@@ -69,7 +73,7 @@ if(WIN32)
)
FetchContent_GetProperties(tray)
if(NOT tray_POPULATED)
FetchContent_Populate(tray)
FetchContent_MakeAvailable(tray)
add_library(tray::tray INTERFACE IMPORTED)
set_target_properties(tray::tray PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${tray_SOURCE_DIR}"
@@ -78,26 +82,26 @@ if(WIN32)
endif()


##### argtable
# argtable
FetchContent_Declare(
argtable
URL https://github.com/argtable/argtable3/releases/download/v3.2.1.52f24e5/argtable-v3.2.1.52f24e5-amalgamation.tar.gz
URL https://github.com/argtable/argtable3/releases/download/v3.2.2.f25c624/argtable-v3.2.2.f25c624-amalgamation.tar.gz
)
FetchContent_GetProperties(argtable)
if(NOT argtable_POPULATED)
FetchContent_Populate(argtable)
FetchContent_MakeAvailable(argtable)
add_library(argtable::argtable INTERFACE IMPORTED)
set_target_properties(argtable::argtable PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${argtable_SOURCE_DIR}/"
INTERFACE_SOURCES "${argtable_SOURCE_DIR}/argtable3.c"
)
endif()


##### executable
add_executable(live-paper
# executable
add_executable(live-paper
$<$<PLATFORM_ID:Windows>:src/platform_windows.c;assets/win.rc>
$<$<PLATFORM_ID:Linux>:src/platform_linux.c>
$<$<PLATFORM_ID:Darwin>:src/platform_macos.c>
src/main.c src/fail.c src/video.c
)
set_target_properties(live-paper PROPERTIES
21 changes: 9 additions & 12 deletions src/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
@@ -27,25 +26,22 @@ void ClearContext(struct Context *context) {
PlatformCleanup(context);
SDL_Quit();
if (context->file) free(context->file);
memset(&context, 0, sizeof(context));
memset(context, 0, sizeof(*context));
}

void ProcessArguments(int argc, char *argv[], struct Context *context) {
const char progname[] = "live-paper";
struct arg_lit *help;
struct arg_str *fit;
struct arg_lit *cache;
struct arg_str *fit;
struct arg_file *file;
struct arg_end *end;
void *argtable[] = {
help = arg_lit0("h", "help", "= display this help and exit"),
fit = arg_str0(NULL, "fit-mode", "<mode>", ""),
arg_rem(NULL, "= controls the way the wallpaper is fit on screen"),
arg_rem(NULL, " possible values: fit, fill, center"),
cache = arg_lit0(NULL, "cache", "= decode all frames at once and store them in memory"),
arg_rem(NULL, " this option is available for short clips only (<=16 frames)"),
arg_rem(NULL, "= controls the way the wallpaper is fit on screen"),
arg_rem(NULL, " possible values: fit, fill, center"),
file = arg_file0(NULL, NULL, "<file>", "= video or animation file to display"),
end = arg_end(20)
end = arg_end(20),
};
if (arg_nullcheck(argtable) != 0) FAIL();
int nerrors = arg_parse(argc, argv, argtable);
@@ -54,8 +50,10 @@ void ProcessArguments(int argc, char *argv[], struct Context *context) {
arg_print_syntax(stdout, argtable, "\n");
printf("Display a video or an animated file as desktop background.\n\n");
arg_print_glossary(stdout, argtable, " %-12s %s\n");
printf("\nExamples: %s loop.mp4\n"
" %s --fit-mode=fill --cache wallpaper.gif\n",
printf(
"\n"
"Examples: %s loop.mp4\n"
" %s --fit-mode=fill wallpaper.gif\n",
progname, progname);
exit(0);
}
@@ -76,7 +74,6 @@ void ProcessArguments(int argc, char *argv[], struct Context *context) {
exit(1);
}

context->cache = (cache->count > 0);
context->fit = FIT_FIT;
if (fit->count) {
if (strcmp(fit->sval[0], "fill") == 0) context->fit = FIT_FILL;
1 change: 0 additions & 1 deletion src/platform.h
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@ struct Context {

char *file;
int fit;
bool cache;
};

void PlatformInitGuiMode(struct Context *context);
23 changes: 23 additions & 0 deletions src/platform_macos.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "platform.h"

#include <SDL.h>

#include "fail.h"

void PlatformInitGuiMode(struct Context *context) {}

void PlatformInit(struct Context *context)
{
context->window = SDL_CreateWindow("LivePaper TEST", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1000, 500, SDL_WINDOW_SHOWN);
if (context->window == NULL)
FAIL_WITH("can't create SDL window");
}

void PlatformUpdate(struct Context *context) {}

void PlatformCleanup(struct Context *context)
{
if (context->window)
SDL_DestroyWindow(context->window);
context->window = NULL;
}
128 changes: 47 additions & 81 deletions src/video.c
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>

#include "fail.h"
#include "platform.h"
@@ -21,6 +22,7 @@ struct Video {
AVCodecContext *decoder_ctx;
AVFormatContext *input_ctx;
struct SwsContext *sws_ctx;
AVFrame *sws_frame;
int stream_id;
double time_base;

@@ -29,9 +31,6 @@ struct Video {

SDL_Texture *tex;
SDL_Rect tex_dest;

struct CacheEntry *cache;
int cache_size;
};

static bool DecodeNextFrame(AVFrame *frame, double *frame_end_time, struct Video *v) {
@@ -55,21 +54,21 @@ static bool DecodeNextFrame(AVFrame *frame, double *frame_end_time, struct Video
continue; // read frame again
}

*frame_end_time = (frame->best_effort_timestamp + frame->pkt_duration)*v->time_base;
*frame_end_time = frame->best_effort_timestamp*v->time_base + frame->duration*av_q2d(frame->time_base);
return true;
}
av_packet_unref(&packet);
}
}

struct Video* VideoLoad(const struct Context *ctx) {
struct Video *VideoLoad(const struct Context *ctx) {
struct Video *v = av_mallocz(sizeof(struct Video));

if (avformat_open_input(&v->input_ctx, ctx->file, NULL, NULL) != 0)
FAIL_WITH("Can't open file '%s'", ctx->file);
if (avformat_find_stream_info(v->input_ctx, NULL) < 0)
FAIL_WITH("Can't find stream information");
AVCodec *codec = NULL;
const AVCodec *codec = NULL;
v->stream_id = av_find_best_stream(v->input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
if (v->stream_id < 0) FAIL();

@@ -82,14 +81,22 @@ struct Video* VideoLoad(const struct Context *ctx) {

int w = v->decoder_ctx->width;
int h = v->decoder_ctx->height;
enum AVPixelFormat target_fmt = AV_PIX_FMT_RGB24;
v->sws_ctx = sws_getContext( // convert to RGB24, no resize
w, h, v->decoder_ctx->pix_fmt,
w, h, AV_PIX_FMT_RGB24,
w, h, target_fmt,
SWS_BILINEAR,
NULL,
NULL,
NULL
);
NULL);
if (v->sws_ctx == NULL)
FAIL();
v->sws_frame = av_frame_alloc();
v->sws_frame->format = target_fmt;
v->sws_frame->width = w;
v->sws_frame->height = h;
if (av_frame_get_buffer(v->sws_frame, 32))
FAIL();

int win_w, win_h;
SDL_GetWindowSize(ctx->window, &win_w, &win_h);
@@ -105,36 +112,8 @@ struct Video* VideoLoad(const struct Context *ctx) {
.h = target_h
};
v->tex_dest = dest_rect;

if (!ctx->cache) {
v->tex = SDL_CreateTexture(ctx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, w, h);
if (!v->tex) FAIL_WITH("can't create SDL texture %i x %i pix", w, h);
} else {
int frame_num = (int)stream->nb_frames;
if (frame_num > 16 || frame_num <= 0) FAIL_WITH("can't cache the file with %i frames (16 frames is the maximum allowed)", frame_num);
struct CacheEntry *cache = av_mallocz_array(frame_num, sizeof(struct CacheEntry));
void *frame_rgb = av_malloc(3*w*h);
for (int i = 0;; ++i) {
AVFrame frame = {0};
double frame_end_time = 0.0;
if (!DecodeNextFrame(&frame, &frame_end_time, v)) break;
if (i >= frame_num) FAIL();
if (i && frame_end_time < cache[i-1].frame_end_time) FAIL(); // something wrong with frame order
struct CacheEntry e = {
.tex = SDL_CreateTexture(ctx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STATIC, w, h),
.frame_end_time = frame_end_time
};
if (!e.tex) FAIL_WITH("can't create SDL texture %i x %i pix", w, h);
sws_scale(v->sws_ctx, (uint8_t const * const *)frame.data,
frame.linesize, 0, v->decoder_ctx->height,
(uint8_t* []){frame_rgb, NULL, NULL}, (int [] ){3*w});
if (SDL_UpdateTexture(e.tex, NULL, frame_rgb, 3*w) != 0) FAIL();
cache[i] = e;
}
av_free(frame_rgb);
v->cache = cache;
v->cache_size = frame_num;
}
v->tex = SDL_CreateTexture(ctx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, w, h);
if (!v->tex) FAIL_WITH("can't create SDL texture %i x %i pix", w, h);

return v;
}
@@ -149,63 +128,50 @@ void VideoUpdate(double delta_sec, struct Video *v, const struct Context *ctx) {
assert(v->input_ctx);

v->time += delta_sec;
if (v->time < v->next_frame_time) { // previously rendered frame is still valid, nothing to do here
if (v->time < v->next_frame_time) { // previously rendered frame is still valid, nothing to do here
return;
}

SDL_Texture *texture_to_render = v->tex;
if (ctx->cache) {
double final_end_time = v->cache[v->cache_size - 1].frame_end_time;
if (v->time >= final_end_time) v->time = 0.0;
for (int i = 0; i < v->cache_size; ++i) {
if (v->time < v->cache[i].frame_end_time) {
texture_to_render = v->cache[i].tex;
break;
}
for (bool found_frame = false; !found_frame;) {
AVFrame frame = {0};
double frame_end_time = 0.0;
if (!DecodeNextFrame(&frame, &frame_end_time, v)) {
// no frames left (EOF), restart the video
ResetVideo(v);
v->time = 0.0;
v->next_frame_time = -1.0;
continue;
}
} else {
for (bool found_frame = false; !found_frame;) {
AVFrame frame = {0};
double frame_end_time = 0.0;
if (!DecodeNextFrame(&frame, &frame_end_time, v)) {
// no frames left (EOF), restart the video
ResetVideo(v);
v->time = 0.0;
v->next_frame_time = -1.0;
continue;
}
if (frame_end_time < v->next_frame_time) FAIL(); // something wrong with frame order
if (frame_end_time > v->time) {
v->next_frame_time = frame_end_time;

void *pix;
int pitch;
SDL_LockTexture(v->tex, NULL, &pix, &pitch);
sws_scale(v->sws_ctx, (uint8_t const * const *)frame.data,
frame.linesize, 0, v->decoder_ctx->height,
(uint8_t* []){pix, NULL, NULL}, (int [] ){pitch});
SDL_UnlockTexture(v->tex);
found_frame = true;
}

av_frame_unref(&frame);
if (frame_end_time < v->next_frame_time) FAIL(); // something wrong with frame order
if (frame_end_time > v->time) {
found_frame = true;
v->next_frame_time = frame_end_time;

sws_scale(v->sws_ctx, (uint8_t const *const *)frame.data, frame.linesize, 0, v->decoder_ctx->height,
v->sws_frame->data, v->sws_frame->linesize);

void *pix;
int pitch;
SDL_LockTexture(v->tex, NULL, &pix, &pitch);
for (int y = 0; y < v->sws_frame->height; ++y)
memcpy(pix + y * pitch, v->sws_frame->data[0] + y * v->sws_frame->linesize[0], v->sws_frame->width * 3);
SDL_UnlockTexture(v->tex);
}

av_frame_unref(&frame);
}

SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255);
SDL_RenderClear(ctx->renderer);
SDL_RenderCopy(ctx->renderer, texture_to_render, NULL, &v->tex_dest);
SDL_RenderCopy(ctx->renderer, v->tex, NULL, &v->tex_dest);
SDL_RenderPresent(ctx->renderer);
}

void VideoClear(struct Video *v, const struct Context *ctx) {
if (v->tex) SDL_DestroyTexture(v->tex);
if (v->cache) {
for (int i = 0; i < v->cache_size; ++i) SDL_DestroyTexture(v->cache[i].tex);
av_free(v->cache);
}
av_frame_free(&v->sws_frame);
sws_freeContext(v->sws_ctx);
avcodec_close(v->decoder_ctx);
avcodec_free_context(&v->decoder_ctx);
avformat_close_input(&v->input_ctx);
memset(v, 0, sizeof(*v));
av_free(v);

0 comments on commit 21ff3f9

Please sign in to comment.