diff options
| author | 2025-11-30 14:32:51 -0500 | |
|---|---|---|
| committer | 2025-11-30 14:32:51 -0500 | |
| commit | c8412bbedae0fce38db96833732e8ce904721e4c (patch) | |
| tree | 4611046186c714513d042966ce97825df0fecf9e /src/buffer | |
| parent | 0d6d13425015d78606232874498327cabcb0e4e2 (diff) | |
| download | camu-c8412bbedae0fce38db96833732e8ce904721e4c.tar.gz camu-c8412bbedae0fce38db96833732e8ce904721e4c.tar.bz2 camu-c8412bbedae0fce38db96833732e8ce904721e4c.zip | |
Build cleanup and fixes from sink testing
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/buffer')
| -rw-r--r-- | src/buffer/audio.c | 11 | ||||
| -rw-r--r-- | src/buffer/clock.c | 77 | ||||
| -rw-r--r-- | src/buffer/clock.h | 5 | ||||
| -rw-r--r-- | src/buffer/video.c | 14 | ||||
| -rw-r--r-- | src/buffer/video.h | 2 |
5 files changed, 60 insertions, 49 deletions
diff --git a/src/buffer/audio.c b/src/buffer/audio.c index a740111..998662b 100644 --- a/src/buffer/audio.c +++ b/src/buffer/audio.c @@ -10,12 +10,12 @@ #include "common.h" #include "common_internal.h" -#define BUFFER_SIZE 6.0 +#define BUFFER_SIZE 7.0 #define BUFFER_MARK_MIN 3.25 // Must be a most half of the buffer size. #define BUFFER_MARK_BUFFERED 0.35 #ifdef CAMU_AUDIO_BUFFER_FADE -#define FADE_STEP(fmt) (2.50f / (fmt)->sample_rate) +#define FADE_STEP(fmt, down) ((down ? -2.5f : 2.5f) / (fmt)->sample_rate) #define FADE_MIN 0.175f #endif @@ -436,10 +436,9 @@ ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdif f32 step = 0.f; if (buf->pause == PAUSE_FADING || buf->fade.volume != buf->volume.user) { - step = FADE_STEP(fmt); - step *= (buf->pause == PAUSE_FADING || buf->fade.volume > buf->volume.user) ? -1.f : 1.f; - if (buf->volume.user > 1.f) step *= buf->volume.user; - step *= MAX(buf->fade.volume, FADE_MIN); + bool down = (buf->pause == PAUSE_FADING || buf->volume.user < buf->fade.volume); + step = FADE_STEP(fmt, down) * MAX(buf->fade.volume, FADE_MIN) * + ((buf->volume.user > 1.f) ? buf->volume.user : 1.f); // Move faster at >100%. } if (step != 0.f || buf->fade.volume != 1.f) { buf->fade.volume = apply_volume(data, req, fmt, buf->fade.volume, buf->volume.user, step); diff --git a/src/buffer/clock.c b/src/buffer/clock.c index 732185e..356ac56 100644 --- a/src/buffer/clock.c +++ b/src/buffer/clock.c @@ -7,6 +7,11 @@ #define RUNNING 0.0 #define PAUSED -DBL_MAX +// @TODO: +// Stop throwing away precision before we need to. +// Assume calc_tick_offset() could give a negative result at any point. +// Use a tick offset to set local buffer latency in a way that makes more sense. + void camu_clock_init(struct camu_clock *clock, void (*callback)(void *, u8), void *userdata) { clock->callback = callback; @@ -22,28 +27,33 @@ static f64 calc_tick_offset(f64 tick, u64 now, u64 target) } } +static void offset_tick(struct camu_clock *clock, f64 diff) +{ + diff += atomic_load(f64)(&clock->tick, AL_ATOMIC_ACQUIRE); + atomic_store(f64)(&clock->tick, diff, AL_ATOMIC_RELEASE); +} + void camu_clock_set(struct camu_clock *clock, f64 base) { clock->base = base; - clock->offset = 0.0; - al_atomic_store(f64)(&clock->tick, -1.0, AL_ATOMIC_RELAXED); - al_atomic_store(f64)(&clock->pause, PAUSED, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->tick, -1.0, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->pause, PAUSED, AL_ATOMIC_RELAXED); clock->paused_at = 0.0; - al_atomic_store(f64)(&clock->last_pts, base, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->last_pts, base, AL_ATOMIC_RELAXED); } void camu_clock_seek(struct camu_clock *clock, f64 base, u64 target) { clock->base = base; - clock->offset = 0.0; - al_atomic_store(f64)(&clock->last_pts, base, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->last_pts, base, AL_ATOMIC_RELAXED); if (clock->paused_at == -1.0) { // We are safe to directly edit the tick here. if (target == 0) { - al_atomic_store(f64)(&clock->tick, -1.0, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->tick, -1.0, AL_ATOMIC_RELAXED); } else { - f64 tick = calc_tick_offset(nn_get_tick(), nn_get_timestamp(), target); - al_atomic_store(f64)(&clock->tick, tick, AL_ATOMIC_RELAXED); + f64 tick = nn_get_tick(); + tick = calc_tick_offset(tick, nn_get_timestamp(), target); + atomic_store(f64)(&clock->tick, tick, AL_ATOMIC_RELAXED); } } else { // Don't touch clock->pause here for the sake of sync. This means, @@ -57,28 +67,29 @@ void camu_clock_seek(struct camu_clock *clock, f64 base, u64 target) } } +// Seek to 0 but include the time it took to perform the seek. void camu_clock_loop(struct camu_clock *clock, f64 last_pts) { - // Seek to 0 but include the time it took to perform the seek. - clock->offset += last_pts - clock->base; clock->base = 0.0; + offset_tick(clock, last_pts - clock->base); } +// If late, pause immediately and on resume() there will be a long delay. void camu_clock_pause(struct camu_clock *clock, u64 target) { al_assert(clock->paused_at == -1.0); - f64 tick = nn_get_tick(); + f64 now = nn_get_tick(), tick = now; if (target > 0) { tick = calc_tick_offset(tick, nn_get_timestamp(), target); - al_atomic_store(f64)(&clock->pause, tick, AL_ATOMIC_RELAXED); - } else { - al_atomic_store(f64)(&clock->pause, PAUSED, AL_ATOMIC_RELAXED); } + atomic_store(f64)(&clock->pause, (tick > now) ? tick : -tick, AL_ATOMIC_RELAXED); + clock->paused_at = tick; } +// If late, this will be a catchup. void camu_clock_resume(struct camu_clock *clock, u64 target) { al_assert(clock->paused_at != -1.0); @@ -91,22 +102,23 @@ void camu_clock_resume(struct camu_clock *clock, u64 target) if (clock->paused_at == 0.0) { if (target == 0) { // target = 0 can never be synced. - al_atomic_store(f64)(&clock->tick, -1.0, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->tick, -1.0, AL_ATOMIC_RELAXED); } else { - al_atomic_store(f64)(&clock->tick, tick, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->tick, tick, AL_ATOMIC_RELAXED); } } else { - clock->offset += tick - clock->paused_at; + f64 pause = atomic_load(f64)(&clock->pause, AL_ATOMIC_ACQUIRE); + offset_tick(clock, tick - ((pause != PAUSED) ? -pause : clock->paused_at)); } - al_atomic_store(f64)(&clock->pause, RUNNING, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->pause, RUNNING, AL_ATOMIC_RELEASE); clock->paused_at = -1.0; } bool camu_clock_is_paused(struct camu_clock *clock) { - return al_atomic_load(f64)(&clock->pause, AL_ATOMIC_RELAXED) == PAUSED; + return atomic_load(f64)(&clock->pause, AL_ATOMIC_RELAXED) < 0.0; } f64 camu_clock_get_base_pts(struct camu_clock *clock) @@ -116,35 +128,34 @@ f64 camu_clock_get_base_pts(struct camu_clock *clock) f64 camu_clock_get_pts(struct camu_clock *clock, f64 latency, bool allow_set) { - f64 pause = al_atomic_load(f64)(&clock->pause, AL_ATOMIC_ACQUIRE); - if (pause == PAUSED) return CAMU_PTS_PAUSED; + f64 pause = atomic_load(f64)(&clock->pause, AL_ATOMIC_RELAXED); + if (pause < 0.0) return CAMU_PTS_PAUSED; f64 current = nn_get_tick(); - - f64 tick = al_atomic_load(f64)(&clock->tick, AL_ATOMIC_RELAXED); + f64 tick = atomic_load(f64)(&clock->tick, AL_ATOMIC_RELAXED); if (tick == -1.0) { if (allow_set) { - tick = al_atomic_compare_and_swap(f64)(&clock->tick, -1.0, current); + tick = atomic_compare_and_swap(f64)(&clock->tick, -1.0, current); if (tick == -1.0) tick = current; } else { return CAMU_PTS_PAUSED; } } + f64 pts = clock->base + (current - tick); + bool signal_pause = false; - if (pause > 0.0 && current > pause) { // pause > 0.0 means running or pause armed. - current = pause; - pause = al_atomic_compare_and_swap(f64)(&clock->pause, pause, PAUSED); - if (pause != PAUSED) { + if (pause > 0.0 && current > pause) { // pause > 0.0 = RUNNING or armed for pause. + f64 paused_at = -current; + pause = atomic_compare_and_swap(f64)(&clock->pause, pause, paused_at); + if (pause != paused_at) { clock->callback(clock->userdata, CAMU_CLOCK_PAUSED); signal_pause = true; } } - f64 pts = (clock->base - clock->offset) + (current - tick); - if (allow_set) { - al_atomic_store(f64)(&clock->last_pts, pts, AL_ATOMIC_RELAXED); + atomic_store(f64)(&clock->last_pts, pts, AL_ATOMIC_RELAXED); } return signal_pause ? CAMU_PTS_SIGNAL_PAUSE : pts + latency; @@ -152,5 +163,5 @@ f64 camu_clock_get_pts(struct camu_clock *clock, f64 latency, bool allow_set) f64 camu_clock_get_last_pts(struct camu_clock *clock) { - return al_atomic_load(f64)(&clock->last_pts, AL_ATOMIC_RELAXED); + return atomic_load(f64)(&clock->last_pts, AL_ATOMIC_RELAXED); } diff --git a/src/buffer/clock.h b/src/buffer/clock.h index 3209119..8324b6a 100644 --- a/src/buffer/clock.h +++ b/src/buffer/clock.h @@ -23,8 +23,8 @@ // Next/Prev: // - User input -> swap -#define CAMU_PTS_PAUSED 0xffffffffffffffff -#define CAMU_PTS_SIGNAL_PAUSE 0x7fffffffffffffff +#define CAMU_PTS_PAUSED ((f64)0xffffffffffffffff) +#define CAMU_PTS_SIGNAL_PAUSE ((f64)0x7fffffffffffffff) #define CAMU_PTS_CONSIDER_PAUSED(pts) (pts == CAMU_PTS_PAUSED || pts == CAMU_PTS_SIGNAL_PAUSE) enum { @@ -33,7 +33,6 @@ enum { struct camu_clock { f64 base; - f64 offset; atomic(f64) tick; atomic(f64) pause; f64 paused_at; diff --git a/src/buffer/video.c b/src/buffer/video.c index e5c38a6..5011e9d 100644 --- a/src/buffer/video.c +++ b/src/buffer/video.c @@ -30,6 +30,7 @@ bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *cl buf->single_frame = true; buf->queue = NULL; buf->buffered = false; + buf->weighted_first_read = false; al_atomic_store(u8)(&buf->flow, FLOWING, AL_ATOMIC_RELAXED); #ifdef CAMU_SCREEN_THREADED al_atomic_store(u8)(&buf->ref, 0, AL_ATOMIC_RELAXED); @@ -63,13 +64,13 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code } else { al_assert(frame_rate.den > 0); buf->avg_frame_duration = av_q2d(av_inv_q(frame_rate)); + buf->weighted_first_read = true; log_info("Stream: %s (%ux%u) VIDEO %.3ffps.", format_name, fmt->width, fmt->height, av_q2d(frame_rate)); } break; } #endif } - buf->weighted_read = !buf->single_frame; struct camu_video_format *in = &buf->fmt.in; struct camu_video_format *req = &buf->fmt.req; camu_video_format_copy(in, fmt); @@ -233,7 +234,8 @@ bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out, bool *weig f64 base_pts = al_atomic_load(f64)(&buf->pts, AL_ATOMIC_ACQUIRE); if (!buf->single_frame) { - f64 pts = camu_clock_get_pts(buf->clock, buf->latency, !buf->weighted_read); + bool set_clock = !buf->weighted_first_read; + f64 pts = camu_clock_get_pts(buf->clock, buf->latency, set_clock); if (!CAMU_PTS_CONSIDER_PAUSED(pts) && pts > base_pts) { base_pts = pts; } @@ -268,15 +270,15 @@ bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out, bool *weig } if (ret == CAMU_QUEUE_OK) { - if (UNLIKELY(buf->weighted_read)) { - *weighted = buf->weighted_read; - buf->weighted_read = false; - } // Only updating buf->pts on QUEUE_OK affects the behavior when we fall completely behind. // Setting it here will result in laggily displaying out of date frames as they come in. // Setting it on every read() will cause the video to freeze. // This option ignores sync but is easier for the user to understand what's happening. al_atomic_store(f64)(&buf->pts, base_pts, AL_ATOMIC_RELEASE); + if (UNLIKELY(buf->weighted_first_read)) { + *weighted = true; + buf->weighted_first_read = false; + } } else if (ret == CAMU_QUEUE_MORE) { log_trace("Underrun."); } diff --git a/src/buffer/video.h b/src/buffer/video.h index fdd7d0b..20644bc 100644 --- a/src/buffer/video.h +++ b/src/buffer/video.h @@ -30,7 +30,7 @@ struct camu_video_buffer { // Need to manually trigger EOF in read(). bool buffered_with_one_frame; // Flush the renderer on this read and don't allow it to set the clock. - bool weighted_read; + bool weighted_first_read; atomic(u8) flow; |