summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2025-08-14 10:59:42 -0400
committerAndrew Opalach <andrew@akon.city> 2025-08-14 10:59:42 -0400
commitc48a6d1e806d7bd92cad81eaffe734f8bf9e40f5 (patch)
treed4cb5610f2f7fde2e2975679721aea7e17352ada /src
parent7e796649557bfeae6eccba751d4a1ffae75de45c (diff)
downloadcamu-c48a6d1e806d7bd92cad81eaffe734f8bf9e40f5.tar.gz
camu-c48a6d1e806d7bd92cad81eaffe734f8bf9e40f5.tar.bz2
camu-c48a6d1e806d7bd92cad81eaffe734f8bf9e40f5.zip
Support 360 degree videos, Improve VR keybinds
- Update liana API in cdio handler. - Fix some build configurations. Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src')
-rw-r--r--src/cache/handlers/cdio.c9
-rw-r--r--src/cache/handlers/http.c9
-rw-r--r--src/codec/codecs.c16
-rw-r--r--src/liana/handlers/cdio_server.c10
-rw-r--r--src/liana/handlers/codec_server.c2
-rw-r--r--src/libsink/desktop.c4
-rw-r--r--src/render/queue_libplacebo.c6
-rw-r--r--src/render/renderer_libplacebo.c17
-rw-r--r--src/render/shaders/vr_video.h37
-rw-r--r--src/screen/screen.c46
-rw-r--r--src/screen/screen.h6
-rw-r--r--src/screen/view.c2
-rw-r--r--src/screen/view.h8
13 files changed, 109 insertions, 63 deletions
diff --git a/src/cache/handlers/cdio.c b/src/cache/handlers/cdio.c
index abebeb0..29126c0 100644
--- a/src/cache/handlers/cdio.c
+++ b/src/cache/handlers/cdio.c
@@ -1,6 +1,8 @@
#define AL_LOG_SECTION "cache_cdio"
#include <al/log.h>
+#include "../../codec/codec.h"
+
#include "../backings/file.h"
#include "../backings/memory.h"
#include "../threaded_waits.h"
@@ -106,6 +108,12 @@ static bool handler_cdio_wait_for_range(struct cch_handler *handler, struct cch_
return cch_threaded_wait_for_range(&cdio->waits, cdio->backing, wait);
}
+static s32 handler_cdio_guess_format(struct cch_handler *handler)
+{
+ (void)handler;
+ return CAMU_CODEC_FALLBACK;
+}
+
static void handler_cdio_free(struct cch_handler **handler)
{
struct cch_handler_cdio *cdio = (struct cch_handler_cdio *)*handler;
@@ -196,6 +204,7 @@ struct cch_entry *cch_handler_cdio_create(void)
entry->handler->can_seek = handler_cdio_can_seek;
entry->handler->maybe_spawn_worker = handler_cdio_maybe_spawn_worker;
entry->handler->wait_for_range = handler_cdio_wait_for_range;
+ entry->handler->guess_format = handler_cdio_guess_format;
entry->handler->free = handler_cdio_free;
entry->handler->entry = entry;
al_str_from(&entry->handler->handler, "cdio");
diff --git a/src/cache/handlers/http.c b/src/cache/handlers/http.c
index 1691ea9..9e99b8a 100644
--- a/src/cache/handlers/http.c
+++ b/src/cache/handlers/http.c
@@ -1,6 +1,8 @@
#define AL_LOG_SECTION "cache_http"
#include <al/log.h>
+#include "../../codec/codec.h"
+
#include "../backings/memory.h"
//#include "../backings/file.h"
#include "../threaded_waits.h"
@@ -91,6 +93,12 @@ static bool handler_http_wait_for_range(struct cch_handler *handler, struct cch_
return cch_threaded_wait_for_range(&http->waits, http->backing, wait);
}
+static s32 handler_http_guess_format(struct cch_handler *handler)
+{
+ (void)handler;
+ return CAMU_CODEC_FALLBACK;
+}
+
static void handler_http_free(struct cch_handler **handler)
{
struct cch_handler_http *http = (struct cch_handler_http *)*handler;
@@ -119,6 +127,7 @@ struct cch_entry *cch_handler_http_create(str *url, struct nn_event_loop *loop)
entry->handler->can_seek = handler_http_can_seek;
entry->handler->maybe_spawn_worker = handler_http_maybe_spawn_worker;
entry->handler->wait_for_range = handler_http_wait_for_range;
+ entry->handler->guess_format = handler_http_guess_format;
entry->handler->free = handler_http_free;
entry->handler->entry = entry;
al_str_from(&entry->handler->handler, "codec");
diff --git a/src/codec/codecs.c b/src/codec/codecs.c
index 7374517..6d830d2 100644
--- a/src/codec/codecs.c
+++ b/src/codec/codecs.c
@@ -2,20 +2,20 @@
#include "codec.h"
#ifdef LIANA_SERVER
-#include "../../codec/wuffs/demuxer.h"
-#include "../../codec/stb_image/demuxer.h"
-#include "../../codec/spng/demuxer.h"
+#include "wuffs/demuxer.h"
+#include "stb_image/demuxer.h"
+#include "spng/demuxer.h"
#ifdef CAMU_HAVE_FFMPEG
-#include "../../codec/ffmpeg/demuxer.h"
+#include "ffmpeg/demuxer.h"
#endif
#endif
#ifdef LIANA_CLIENT
-#include "../../codec/wuffs/decoder.h"
-#include "../../codec/stb_image/decoder.h"
-#include "../../codec/spng/decoder.h"
+#include "wuffs/decoder.h"
+#include "stb_image/decoder.h"
+#include "spng/decoder.h"
#ifdef CAMU_HAVE_FFMPEG
-#include "../../codec/ffmpeg/decoder.h"
+#include "ffmpeg/decoder.h"
#endif
#endif
diff --git a/src/liana/handlers/cdio_server.c b/src/liana/handlers/cdio_server.c
index 0fafae7..54c63ab 100644
--- a/src/liana/handlers/cdio_server.c
+++ b/src/liana/handlers/cdio_server.c
@@ -29,12 +29,14 @@ static bool cdio_server_init(struct lia_server_handler *handler, struct cch_hand
static void cdio_server_write_info(struct lia_server_handler *handler, struct nn_packet *packet)
{
struct lia_cdio_server *cdio = (struct lia_cdio_server *)handler;
- nn_packet_write_u64(packet, 0);
- nn_packet_write_u32(packet, 1);
+ u64 duration = cdio->handler.get_duration(&cdio->handler);
+ nn_packet_write_u64(packet, duration);
+ nn_packet_write_u32(packet, 1); // 1 stream.
+ nn_packet_write_str(packet, &al_str_c("pcm_s16le"));
nn_packet_write_u8(packet, CAMU_NORMAL);
nn_packet_write_u8(packet, CAMU_STREAM_AUDIO);
- nn_packet_write_u64(packet, cdio->handler.get_duration(&cdio->handler));
- nn_packet_write_s32(packet, 0);
+ nn_packet_write_u64(packet, duration);
+ nn_packet_write_s32(packet, 0); // index.
nn_packet_write_s32(packet, cdio->fmt.format);
nn_packet_write_s32(packet, cdio->fmt.sample_rate);
nn_packet_write_s32(packet, cdio->fmt.channel_count);
diff --git a/src/liana/handlers/codec_server.c b/src/liana/handlers/codec_server.c
index 801a3e1..fbb1e72 100644
--- a/src/liana/handlers/codec_server.c
+++ b/src/liana/handlers/codec_server.c
@@ -103,9 +103,11 @@ static bool codec_server_seek(struct lia_server_handler *handler, u64 pos)
static void codec_server_step(struct lia_server_handler *handler)
{
struct lia_codec_server *codec = (struct lia_codec_server *)handler;
+#ifdef CAMU_HAVE_FFMPEG
#ifdef CAMU_DIRECT_MODE
codec->packet.av.pkt = av_packet_alloc();
#endif
+#endif
codec->handler.status = codec->demux->get_packet(codec->demux, &codec->packet);
}
diff --git a/src/libsink/desktop.c b/src/libsink/desktop.c
index 12008fd..6dee662 100644
--- a/src/libsink/desktop.c
+++ b/src/libsink/desktop.c
@@ -133,7 +133,7 @@ static void log_sink_status(struct camu_desktop *c)
}
bool show_hour = duration > 60u * 60u * 1000000u;
- s32 offset = al_snprintf(status, sizeof(status), paused ? "⏸ " : "⏵ ");
+ s32 offset = al_snprintf(status, sizeof(status), paused ? "|| " : "|> ");
offset += al_snprintf(status + offset, sizeof(status) - offset, "[");
offset += camu_print_time(status + offset, sizeof(status) - offset, pts, show_hour, 2);
offset += al_snprintf(status + offset, sizeof(status) - offset, "/");
@@ -208,6 +208,8 @@ bool camu_desktop_open(struct camu_desktop *c, const char *window_name)
if (!camu_screen_create_renderer(&c->scr, c->renderer)) {
return false;
}
+ // Need to render twice for the window to show early.
+ c->renderer->render(c->renderer, &c->scr, true);
c->renderer->render(c->renderer, &c->scr, true);
#ifdef DESKTOP_NULL_AUDIO
if (!camu_mixer_init(&c->mixer, (struct camu_audio *)&audio_plugin_null)) {
diff --git a/src/render/queue_libplacebo.c b/src/render/queue_libplacebo.c
index 01cd366..d1f7d88 100644
--- a/src/render/queue_libplacebo.c
+++ b/src/render/queue_libplacebo.c
@@ -256,10 +256,10 @@ static bool map_av_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *
#ifdef CAMU_HAVE_SUBTITLES
if (ok && lq->has_subtitles) {
- s64 now = av_rescale_q(frame->best_effort_timestamp, stream->time_base, (AVRational){ 1, 1000 });
+ s64 pts = av_rescale_q(frame->best_effort_timestamp, stream->time_base, (AVRational){ 1, 1000 });
nn_mutex_lock(&lq->subtitle_lock);
s32 change; // 1 = different position, 2 = different content.
- ASS_Image *ass_frame = ass_render_frame(lq->ass_renderer, lq->ass_track, now, &change);
+ ASS_Image *ass_frame = ass_render_frame(lq->ass_renderer, lq->ass_track, pts, &change);
if (ass_frame) {
struct camu_overlay_lp *overlay = NULL;
if (lq->overlays.count > 0) overlay = al_array_last(lq->overlays);
@@ -272,6 +272,8 @@ static bool map_av_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *
out_frame->overlays = overlay->overlays;
out_frame->num_overlays = overlay->num;
((struct pl_source_frame *)src)->frame_data = overlay;
+ } else if (change > 0) {
+ log_error("Failed to parse or render subtitle.");
}
nn_mutex_unlock(&lq->subtitle_lock);
}
diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c
index cdf09bf..562c486 100644
--- a/src/render/renderer_libplacebo.c
+++ b/src/render/renderer_libplacebo.c
@@ -107,6 +107,8 @@ static void ass_log_callback(s32 level, const char *fmt, va_list args, void *use
(void)userdata;
if (level <= 1) {
al_logv(AL_LOG_ERROR, "ass", fmt, args);
+ } else if (level <= 3) {
+ al_logv(AL_LOG_WARN, "ass", fmt, args);
} else {
#ifdef AL_DEBUG
al_logv(AL_LOG_DEBUG, "ass", fmt, args);
@@ -247,7 +249,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid
}
lr->swapchain = pl_opengl_create_swapchain(lr->gl, pl_opengl_swapchain_params(
- //.max_swapchain_depth = 2,
+ .max_swapchain_depth = 1,
.swap_buffers = gl_swap_buffers,
.priv = priv
));
@@ -391,11 +393,14 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree
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);
+ mouse_x = (scr->last_pointer_x / scr->width) - (scr->vr_calibrate_x - 0.5);
+ mouse_y = (scr->last_pointer_y / scr->height) - (scr->vr_calibrate_y - 0.5);
+ if (scr->vr_emulation == CAMU_VR_360) {
+ mouse_x = CLAMP(mouse_x * 2.0, -1.0, 3.0);
+ } else {
+ mouse_x = CLAMP(mouse_x, -0.5, 1.5);
+ }
+ mouse_y = CLAMP(1.0 - 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;
diff --git a/src/render/shaders/vr_video.h b/src/render/shaders/vr_video.h
index fc2d192..73869eb 100644
--- a/src/render/shaders/vr_video.h
+++ b/src/render/shaders/vr_video.h
@@ -5,12 +5,11 @@
// 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"
+"//!MINIMUM -1.0\n"
+"//!MAXIMUM 3.0\n"
"0.0\n"
"//!PARAM mouse_y\n"
"//!TYPE float\n"
@@ -27,20 +26,20 @@ static const char vr_video_shader[] = \
"//!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"
+" 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";
diff --git a/src/screen/screen.c b/src/screen/screen.c
index d0d78e2..ee6b1e9 100644
--- a/src/screen/screen.c
+++ b/src/screen/screen.c
@@ -40,8 +40,6 @@ static void do_resize(struct camu_screen *scr, u32 width, u32 height)
al_assert(width > 0 && height > 0);
scr->width = width;
scr->height = height;
- scr->calibrate_x = scr->width / 2.0;
- scr->calibrate_y = scr->height / 2.0;
struct camu_screen_video *video;
al_array_foreach_ptr(scr->videos, i, video) {
camu_view_calculate(&video->view, scr->width, scr->height);
@@ -308,8 +306,6 @@ static bool key_callback(void *userdata, u8 state, u16 button)
break;
#endif
case STELA_KEY_R: {
- scr->calibrate_x = scr->last_pointer_x;
- scr->calibrate_y = scr->last_pointer_y;
struct camu_view *view = get_view_from_mouse_pos(scr);
if (view) {
if (SCREEN_MOD2(scr)) {
@@ -344,6 +340,8 @@ static bool key_callback(void *userdata, u8 state, u16 button)
view->rotation = CAMU_VIEW_ROTATION_0;
break;
}
+ } else if (scr->vr_emulation) {
+ view->fov = AL_TO_RADIANS(CAMU_DEFAULT_FOV);
} else {
view->mode = CAMU_DEFAULT_VIEW;
}
@@ -393,19 +391,29 @@ static bool key_callback(void *userdata, u8 state, u16 button)
al_atomic_add(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED);
return true;
case STELA_KEY_V: {
- struct camu_view *view = get_view_from_mouse_pos(scr);
- if (view) {
- view->mode = CAMU_DEFAULT_VIEW;
- camu_view_calculate(view, scr->width, scr->height);
- }
- if (!scr->vr_emulation) {
- scr->flags = (scr->flags & ~CAMU_SCREEN_ZOOM_PAN_SIMPLE) | CAMU_SCREEN_ZOOM_FOV;
- scr->window->set_cursor(scr->window, STELA_CURSOR_HIDDEN);
- scr->vr_emulation = true;
+ if (SCREEN_MOD1(scr)) {
+ scr->vr_calibrate_x = scr->last_pointer_x / scr->width;
+ scr->vr_calibrate_y = scr->last_pointer_y / scr->height;
} else {
- scr->flags = (scr->flags & ~CAMU_SCREEN_ZOOM_FOV) | CAMU_SCREEN_ZOOM_PAN_SIMPLE;
- scr->window->set_cursor(scr->window, STELA_CURSOR_NORMAL);
- scr->vr_emulation = false;
+ struct camu_view *view = get_view_from_mouse_pos(scr);
+ if (SCREEN_MOD2(scr) && scr->vr_emulation == CAMU_VR_180) {
+ scr->vr_emulation = CAMU_VR_360;
+ break;
+ }
+ if (!scr->vr_emulation) {
+ if (view) view->mode = CAMU_VIEW_AUTOFIT;
+ scr->flags = (scr->flags & ~CAMU_SCREEN_ZOOM_PAN_SIMPLE) | CAMU_SCREEN_ZOOM_FOV;
+ scr->window->set_cursor(scr->window, STELA_CURSOR_HIDDEN);
+ scr->vr_emulation = SCREEN_MOD2(scr) ? CAMU_VR_360 : CAMU_VR_180;
+ } else {
+ if (view) view->mode = CAMU_DEFAULT_VIEW;
+ scr->flags = (scr->flags & ~CAMU_SCREEN_ZOOM_FOV) | CAMU_SCREEN_ZOOM_PAN_SIMPLE;
+ scr->window->set_cursor(scr->window, STELA_CURSOR_NORMAL);
+ scr->vr_emulation = CAMU_VR_DISABLED;
+ }
+ if (view) {
+ camu_view_calculate(view, scr->width, scr->height);
+ }
}
break;
}
@@ -466,7 +474,9 @@ bool camu_screen_init(struct camu_screen *scr)
#ifdef CAMU_SCREEN_DRAG_SEEK
scr->last_seek_ts = 0;
#endif
- scr->vr_emulation = false;
+ scr->vr_emulation = CAMU_VR_DISABLED;
+ scr->vr_calibrate_x = 0.5;
+ scr->vr_calibrate_y = 0.5;
al_array_init(scr->videos);
#ifdef CAMU_SCREEN_THREADED
al_array_init(scr->add_queue);
@@ -499,8 +509,6 @@ bool camu_screen_create_window(struct camu_screen *scr, const char *name)
}
scr->width = scr->window->width;
scr->height = scr->window->height;
- scr->calibrate_x = scr->width / 2.0;
- scr->calibrate_y = scr->height / 2.0;
scr->fullscreen = false;
scr->scaling_disabled = false;
scr->transparent_background = false;
diff --git a/src/screen/screen.h b/src/screen/screen.h
index 4c6e205..e03fdb3 100644
--- a/src/screen/screen.h
+++ b/src/screen/screen.h
@@ -75,9 +75,9 @@ struct camu_screen {
#ifdef CAMU_SCREEN_DRAG_SEEK
u64 last_seek_ts;
#endif
- f64 calibrate_x;
- f64 calibrate_y;
- bool vr_emulation;
+ u8 vr_emulation;
+ f64 vr_calibrate_x;
+ f64 vr_calibrate_y;
array(struct camu_screen_video) videos;
#ifdef CAMU_SCREEN_THREADED
array(struct camu_video_buffer *) add_queue;
diff --git a/src/screen/view.c b/src/screen/view.c
index 4719062..81d19a9 100644
--- a/src/screen/view.c
+++ b/src/screen/view.c
@@ -27,7 +27,7 @@ void camu_view_init(struct camu_view *view, u32 width, u32 height)
view->height = height;
view->zindex = 0;
view->stretch = 1.0;
- view->fov = AL_TO_RADIANS(80.0);
+ view->fov = AL_TO_RADIANS(CAMU_DEFAULT_FOV);
}
void camu_view_calculate(struct camu_view *view, u32 window_width, u32 window_height)
diff --git a/src/screen/view.h b/src/screen/view.h
index 2fc1742..5fd86c0 100644
--- a/src/screen/view.h
+++ b/src/screen/view.h
@@ -17,8 +17,16 @@ enum {
CAMU_VIEW_ROTATION_360
};
+enum {
+ CAMU_VR_DISABLED = 0,
+ CAMU_VR_180,
+ CAMU_VR_360
+};
+
#define CAMU_DEFAULT_VIEW CAMU_VIEW_AUTOFIT
+#define CAMU_DEFAULT_FOV 80.0
+
struct camu_view {
u8 mode;
u8 rotation;