diff options
| author | 2025-06-23 17:49:11 -0400 | |
|---|---|---|
| committer | 2025-06-23 17:49:11 -0400 | |
| commit | e0fcbf0910b52a6e66eb733a2850ec58a53cf0e3 (patch) | |
| tree | a24ff2b9313263666d121536064e01436b480571 /src/render | |
| parent | e9475ce94ba69bd437d8cf0cf3f78062be928568 (diff) | |
| download | camu-e0fcbf0910b52a6e66eb733a2850ec58a53cf0e3.tar.gz camu-e0fcbf0910b52a6e66eb733a2850ec58a53cf0e3.tar.bz2 camu-e0fcbf0910b52a6e66eb733a2850ec58a53cf0e3.zip | |
Improve FFmpeg hwaccel fallback, VR emulation
- Optimize sink seeking with single video frame.
- Small cleanups.
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/render')
| -rw-r--r-- | src/render/meson.build | 2 | ||||
| -rw-r--r-- | src/render/queue_libplacebo.c | 20 | ||||
| -rw-r--r-- | src/render/renderer_libplacebo.c | 64 | ||||
| -rw-r--r-- | src/render/renderer_libplacebo.h | 1 | ||||
| -rw-r--r-- | src/render/shaders/vr_video.h | 46 |
5 files changed, 101 insertions, 32 deletions
diff --git a/src/render/meson.build b/src/render/meson.build index b7927bb..af68036 100644 --- a/src/render/meson.build +++ b/src/render/meson.build @@ -128,7 +128,7 @@ endif if get_option('subtitles').enabled() libass = dependency('libass', required: false, allow_fallback: false) if not libass.found() - libass_opts = [] + libass_opts = ['test=disabled'] if not is_windows libass_opts += ['fontconfig=enabled'] # libass(e46aede):meson.build:126 diff --git a/src/render/queue_libplacebo.c b/src/render/queue_libplacebo.c index 5932944..488c3b5 100644 --- a/src/render/queue_libplacebo.c +++ b/src/render/queue_libplacebo.c @@ -22,6 +22,7 @@ static bool queue_lp_configure_subtitles(struct camu_frame_queue *queue, u32 wid log_error("Failed to initialize ass renderer."); return false; } + ass_set_shaper(lq->ass_renderer, ASS_SHAPING_COMPLEX); lq->ass_track = ass_new_track(lq->ass); if (!lq->ass_track) { log_error("Failed to create ass track."); @@ -49,7 +50,7 @@ static bool queue_lp_configure_subtitles(struct camu_frame_queue *queue, u32 wid static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src, struct pl_frame *out_frame) { - struct camu_codec_frame *frame = src->frame_data; + struct camu_codec_frame *frame = (struct camu_codec_frame *)src->frame_data; u64 masks[4] = { 0 }; s32 pixel_stride; @@ -120,7 +121,7 @@ static void unmap_frame(pl_gpu gpu, struct pl_frame *frame, const struct pl_sour static void discard_frame(const struct pl_source_frame *src) { - struct camu_codec_frame *frame = src->frame_data; + struct camu_codec_frame *frame = (struct camu_codec_frame *)src->frame_data; camu_codec_frame_discard(frame); } @@ -142,7 +143,6 @@ static void queue_lp_push(struct camu_frame_queue *queue, struct camu_codec_fram static struct camu_overlay_lp *create_subtitle_overlay(pl_gpu gpu, ASS_Image *ass_frame) { struct camu_overlay_lp *overlay = al_alloc_object(struct camu_overlay_lp); - for (; ass_frame; ass_frame = ass_frame->next) { pl_tex tex = pl_tex_create(gpu, pl_tex_params( .w = ass_frame->w, @@ -166,14 +166,11 @@ static struct camu_overlay_lp *create_subtitle_overlay(pl_gpu gpu, ASS_Image *as if (overlay->num >= overlay->alloc) { s32 old_alloc = overlay->alloc; overlay->alloc = old_alloc ? al_next_power_of_two(overlay->alloc + 1) : 8; - if (!overlay->overlays) { - overlay->overlays = al_malloc(sizeof(struct pl_overlay) * overlay->alloc); - } else { - overlay->overlays = al_realloc(overlay->overlays, sizeof(struct pl_overlay) * overlay->alloc); - } + overlay->overlays = (struct pl_overlay *)al_realloc(overlay->overlays, + sizeof(struct pl_overlay) * overlay->alloc); for (s32 i = old_alloc; i < overlay->alloc; i++) { current = (struct pl_overlay *)&overlay->overlays[i]; - current->parts = al_malloc(sizeof(struct pl_overlay_part) * 1); + current->parts = (struct pl_overlay_part *)al_malloc(sizeof(struct pl_overlay_part)); current->num_parts = 0; } } @@ -209,7 +206,6 @@ static struct camu_overlay_lp *create_subtitle_overlay(pl_gpu gpu, ASS_Image *as current->coords = PL_OVERLAY_COORDS_SRC_FRAME; current->num_parts = 1; } - return overlay; } #endif @@ -217,7 +213,7 @@ static struct camu_overlay_lp *create_subtitle_overlay(pl_gpu gpu, ASS_Image *as static bool map_av_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src, struct pl_frame *out_frame) { - AVFrame *frame = src->frame_data; + AVFrame *frame = (AVFrame *)src->frame_data; struct camu_frame_queue_lp *lq = (struct camu_frame_queue_lp *)frame->opaque; AVStream *stream = lq->q.buf->stream->av.stream; @@ -316,7 +312,7 @@ static void unmap_av_frame(pl_gpu gpu, struct pl_frame *frame, const struct pl_s static void discard_av_frame(const struct pl_source_frame *src) { - AVFrame *frame = src->frame_data; + AVFrame *frame = (AVFrame *)src->frame_data; av_frame_free(&frame); log_warn("Dropped frame with PTS %.3f.", src->pts); } diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c index 5ef2a34..191c40d 100644 --- a/src/render/renderer_libplacebo.c +++ b/src/render/renderer_libplacebo.c @@ -15,6 +15,8 @@ #include <libplacebo/d3d11.h> #endif +#include "shaders/vr_video.h" + #include "renderer_libplacebo.h" #include "queue_libplacebo.h" @@ -276,19 +278,15 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid lr->params.correct_subpixel_offsets = true; //lr->params.distort_params = pl_distort_params(.unscaled = false); -#if 0 + lr->vr_emulation_hook[0] = pl_mpv_user_shader_parse(lr->gpu, vr_video_shader, sizeof(vr_video_shader) - 1); + /* struct nn_file file; if (nn_file_open(&file, &al_str_c(""), 0)) { char *c_str; size_t length = nn_file_read_as_c_str(&file, &c_str); const struct pl_hook *hook = pl_mpv_user_shader_parse(lr->gpu, (const char *)c_str, length); - const struct pl_hook **hooks = al_malloc(sizeof(struct pl_hook *)); - hooks[0] = al_malloc(sizeof(struct pl_hook)); - al_memcpy((void *)hooks[0], (void *)hook, sizeof(struct pl_hook)); - lr->params.hooks = hooks; - lr->params.num_hooks = 1; } -#endif + */ #ifdef CAMU_HAVE_FFMPEG lr->r.get_buffer2 = pl_get_buffer2; @@ -345,6 +343,19 @@ static u32 renderer_lp_get_latency(struct camu_renderer *renderer) return (u32)pl_swapchain_latency(lr->swapchain); } +// This is a completely broken "hash" of the f64 pts value, but it works for now. +// https://www.virtualdub.org/blog2/entry_259.html +static inline intptr_t float_64_hash(f64 value) +{ + union { f64 f; u64 u; } fv; + fv.f = value; + intptr_t hash = (intptr_t)fv.u; +#ifdef AL_WE_32BIT + hash += (intptr_t)(fv.u >> 32); +#endif + return hash; +} + static void renderer_lp_render(struct camu_renderer *renderer, struct camu_screen *scr, bool force) { struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; @@ -368,6 +379,20 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree lr->have_frame = true; } + f64 mouse_x, mouse_y; + bool vr_emulation = scr->vr_emulation && lr->vr_emulation_hook[0]; + if (vr_emulation) { + mouse_x = (scr->last_pointer_x - (scr->calibrate_x - (scr->width / 2.0))) / (f64)scr->width; + mouse_y = (scr->last_pointer_y - (scr->calibrate_y - (scr->height / 2.0))) / (f64)scr->height; + mouse_y = 1.0 - mouse_y; + mouse_x = CLAMP(mouse_x, -0.5, 1.5); + mouse_y = CLAMP(mouse_y, -0.5, 1.5); + lr->params.hooks = lr->vr_emulation_hook; + lr->params.num_hooks = 1; + lr->params.hooks[0]->parameters[0].data->f = (f32)mouse_x; + lr->params.hooks[0]->parameters[1].data->f = (f32)mouse_y; + } + struct pl_frame *target = &lr->target; struct pl_frame_mix mix; @@ -385,16 +410,15 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree do_gpu_finish |= weighted; // Terrible hack. Lets us distinguish single frames with the same dimensions. // Tied to a libplacebo patch to consider info_priv in the hash. - // Also, add in reset_pts to account for buffer resets. This is a completely - // broken "hash" of the f64 pts value but hopefully it works for now. - // https://www.virtualdub.org/blog2/entry_259.html + // Also, add in reset_pts to account for buffer resets. intptr_t hash = (intptr_t)video->buf; - union { f64 f; u64 u; } pts_hash; - pts_hash.f = video->buf->reset_pts; - hash += (intptr_t)pts_hash.u; -#ifdef AL_WE_32BIT - hash += (intptr_t)(pts_hash.u >> 32); -#endif + hash += float_64_hash(video->buf->reset_pts); + if (vr_emulation) { + hash += float_64_hash(mouse_x); + hash += float_64_hash(mouse_y); + hash += float_64_hash(video->view.fov); + lr->params.hooks[0]->parameters[2].data->f = (f32)video->view.fov; + } lr->params.info_priv = (void *)hash; target->crop = mix.frames[0]->crop; target->crop.x1 *= video->view.zoom / video->view.stretch; @@ -404,9 +428,7 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree target->crop.x1 += video->view.x_offset; target->crop.y1 += video->view.y_offset; target->rotation = video->view.rotation; - //lr->params.color_adjustment = pl_color_adjustment( - // .saturation = 0.0 - //); + //lr->params.color_adjustment = pl_color_adjustment(.saturation = 0.0); pl_render_image_mix(lr->renderer, &mix, target, &lr->params); } } else { @@ -424,6 +446,9 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree } } + lr->params.hooks = NULL; + lr->params.num_hooks = 0; + if (!scr->videos.count && !force) { // Don't spin too hard on a potential error state. nn_thread_sleep(NNWT_TS_FROM_USEC(192)); @@ -462,6 +487,7 @@ void renderer_lp_free(struct camu_renderer **renderer) if (lr->gl) pl_opengl_destroy(&lr->gl); #endif if (lr->logger) pl_log_destroy(&lr->logger); + if (lr->vr_emulation_hook[0]) pl_mpv_user_shader_destroy(&lr->vr_emulation_hook[0]); #ifdef CAMU_HAVE_SUBTITLES if (lr->ass) ass_library_done(lr->ass); #endif diff --git a/src/render/renderer_libplacebo.h b/src/render/renderer_libplacebo.h index a0125ba..c8962d2 100644 --- a/src/render/renderer_libplacebo.h +++ b/src/render/renderer_libplacebo.h @@ -37,6 +37,7 @@ struct camu_renderer_lp { pl_renderer renderer; f64 last_render_tick; struct pl_render_params params; + const struct pl_hook *vr_emulation_hook[1]; #ifdef CAMU_HAVE_SUBTITLES ASS_Library *ass; #endif diff --git a/src/render/shaders/vr_video.h b/src/render/shaders/vr_video.h new file mode 100644 index 0000000..fc2d192 --- /dev/null +++ b/src/render/shaders/vr_video.h @@ -0,0 +1,46 @@ +#pragma once + +// https://gist.github.com/tesu/196db5421559de3e9555d4f9da9d847d +// FOV: [0 to M_PI] horizontal field of view, range is exclusive +// YAW: [any float] polar angle, one full revolution is 2*M_PI +// PITCH: [any float] vertical tilt, positive is up +// ROLL: [any float] view rotation, positive is clockwise +//" const float yaw = M_PI*(-1.0+(mouse_x*2.0));\n" // 360 +static const char vr_video_shader[] = \ +"//!PARAM mouse_x\n" +"//!TYPE float\n" +"//!MINIMUM -0.5\n" +"//!MAXIMUM 1.5\n" +"0.0\n" +"//!PARAM mouse_y\n" +"//!TYPE float\n" +"//!MINIMUM -0.5\n" +"//!MAXIMUM 1.5\n" +"0.5\n" +"//!PARAM fov\n" +"//!TYPE float\n" +"//!MINIMUM 0\n" +"//!MAXIMUM 3.141592653589793\n" +"1.5707963267948966\n" +"//!HOOK MAINPRESUB\n" +"//!BIND HOOKED\n" +"//!DESC un360\n" +"const float M_PI = 3.141592653589793;\n" +"vec4 hook() {\n" +" float yaw = M_PI*mouse_x;\n" +" float pitch = M_PI*(-0.5+mouse_y);\n" +" float roll = M_PI*0.0;\n" +" float t = tan(fov/2);\n" +" float c = cos(pitch);\n" +" float s = sin(pitch);\n" +" float r = target_size.y/target_size.x;\n" +" float sR = sin(roll);\n" +" float cR = cos(roll);\n" +" mat3 m = mat3(2*t*cR, 2*sR*t*r, -t*(cR+sR*r), -2*sR*t*c, 2*cR*t*c*r, t*c*(sR-cR*r)-s, -2*sR*t*s, 2*cR*t*s*r, t*s*(sR-cR*r)+c);\n" +" vec3 p = vec3(HOOKED_pos, 1.0) * m;\n" +" float theta = atan(p.x, p.z) + yaw;\n" +" float phi = atan(p.y, length(p.xz)) + M_PI/2;\n" +" float x = fract(theta / (2*M_PI));\n" +" float y = phi / M_PI;\n" +" return HOOKED_tex(vec2(x, y));\n" +"}\n"; |