summaryrefslogtreecommitdiff
path: root/src/buffer
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer')
-rw-r--r--src/buffer/audio.c48
-rw-r--r--src/buffer/audio.h10
-rw-r--r--src/buffer/common_internal.h10
-rw-r--r--src/buffer/peak_buffer.c14
-rw-r--r--src/buffer/peak_buffer.h6
-rw-r--r--src/buffer/video.c39
6 files changed, 71 insertions, 56 deletions
diff --git a/src/buffer/audio.c b/src/buffer/audio.c
index 707219f..cf42840 100644
--- a/src/buffer/audio.c
+++ b/src/buffer/audio.c
@@ -5,13 +5,13 @@
#endif
#include "audio.h"
+#include "volume.h"
#include "common.h"
#include "common_internal.h"
-#include "volume.h"
-#define BUFFER_SIZE 4.0
-#define BUFFER_MARK_MIN 1.75 // Must be a most half of the buffer size.
-#define BUFFER_MARK_BUFFERED 1.0
+#define BUFFER_SIZE 8.0
+#define BUFFER_MARK_MIN 3.25 // Must be a most half of the buffer size.
+#define BUFFER_MARK_BUFFERED 1.25
#ifdef CAMU_AUDIO_BUFFER_FADE
#define FADE_STEP(fmt) (1.75f / (fmt)->sample_rate)
@@ -37,7 +37,7 @@ static void reset_buffer_state(struct camu_audio_buffer *buf)
#endif
buf->buffered = false;
al_atomic_store(u8)(&buf->flow, FLOWING, AL_ATOMIC_RELAXED);
- al_atomic_store(size_t)(&buf->uncork_at, 0, AL_ATOMIC_RELAXED);
+ al_atomic_store(ptrdiff_t)(&buf->uncork_at, 0, AL_ATOMIC_RELAXED);
}
bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *clock)
@@ -77,12 +77,12 @@ bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_code
in_format_name, buf->fmt.in.channel_count, buf->fmt.in.sample_rate,
req_format_name, buf->fmt.req.channel_count, buf->fmt.req.sample_rate);
- buf->size = camu_audio_format_sec_to_bytes(&buf->fmt.req, BUFFER_SIZE);
+ buf->size = (ptrdiff_t)camu_audio_format_sec_to_bytes(&buf->fmt.req, BUFFER_SIZE);
buf->data = (u8 *)al_malloc(buf->size);
al_ring_buffer_init(&buf->rb, buf->data, buf->size);
- buf->mark.min = camu_audio_format_sec_to_bytes(&buf->fmt.req, BUFFER_MARK_MIN);
- buf->mark.buffered = camu_audio_format_sec_to_bytes(&buf->fmt.req, BUFFER_MARK_BUFFERED);
+ buf->mark.min = (ptrdiff_t)camu_audio_format_sec_to_bytes(&buf->fmt.req, BUFFER_MARK_MIN);
+ buf->mark.buffered = (ptrdiff_t)camu_audio_format_sec_to_bytes(&buf->fmt.req, BUFFER_MARK_BUFFERED);
camu_peak_buffer_init(&buf->peak, KB(16));
buf->stream = stream;
@@ -118,12 +118,6 @@ void camu_audio_buffer_set_no_video(struct camu_audio_buffer *buf, bool no_video
#define BUFFERED_SECONDS_DEBUG(buf) 0
#endif
-static inline bool frame_is_late(struct camu_clock *clock, f64 base, f64 pts, f64 duration)
-{
- if (base == -1.0) base = camu_clock_get_base_pts(clock);
- return pts + duration < base;
-}
-
// A return value of false signals that we pushed to the peak buffer.
static bool push_internal(struct camu_audio_buffer *buf, f64 pts, u8 **data, s32 sample_count)
{
@@ -157,15 +151,15 @@ static bool push_internal(struct camu_audio_buffer *buf, f64 pts, u8 **data, s32
return true;
}
- size_t space = al_ring_buffer_space(&buf->rb);
+ ptrdiff_t space = al_ring_buffer_space(&buf->rb);
if (!buf->buffered && buf->size - space > buf->mark.buffered) {
al_log_debug("audio_buffer", "Buffered (mark: %.2fs).", BUFFERED_SECONDS_DEBUG(buf));
buf->callback(buf->userdata, CAMU_BUFFER_BUFFERED);
buf->buffered = true;
}
- size_t have = camu_audio_format_samples_to_bytes(&buf->fmt.req, (size_t)sample_count);
- size_t peak = camu_peak_buffer_get_size(&buf->peak);
+ ptrdiff_t have = (ptrdiff_t)camu_audio_format_samples_to_bytes(&buf->fmt.req, sample_count);
+ ptrdiff_t peak = camu_peak_buffer_get_size(&buf->peak);
if (space < have + peak) {
al_assert(have < buf->mark.min);
camu_peak_buffer_push(&buf->peak, data[0], have);
@@ -178,7 +172,7 @@ static bool push_internal(struct camu_audio_buffer *buf, f64 pts, u8 **data, s32
}
al_assert(peak <= buf->mark.min);
// We adjust the min mark by the peak buffer size just for consistency.
- al_atomic_store(size_t)(&buf->uncork_at, buf->mark.min - peak, AL_ATOMIC_RELAXED);
+ al_atomic_store(ptrdiff_t)(&buf->uncork_at, buf->mark.min - peak, AL_ATOMIC_RELAXED);
buf->callback(buf->userdata, CAMU_BUFFER_CORK);
return false;
}
@@ -264,7 +258,7 @@ void camu_audio_buffer_unpause(struct camu_audio_buffer *buf)
// PAUSE_PAUSED signifies that the last read was silence. Meaning we can skip
// around in the buffer without worrying about pops.
-size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t req)
+ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdiff_t req)
{
if (al_atomic_load(s32)(&buf->volume.set, AL_ATOMIC_ACQUIRE) > 0) {
buf->volume.user = al_atomic_load(f32)(&buf->volume.queued, AL_ATOMIC_RELAXED);
@@ -315,8 +309,8 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re
}
struct camu_audio_format *fmt = &buf->fmt.req;
- size_t ret, signal = req;
- size_t have = al_ring_buffer_occupied(&buf->rb);
+ ptrdiff_t ret, signal = req;
+ ptrdiff_t have = al_ring_buffer_occupied(&buf->rb);
#ifdef CAMU_AUDIO_BUFFER_FADE
// Cut off fade if it's reaching too far.
if (have < buf->fade.offset) have = 0;
@@ -329,16 +323,16 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re
if (!buf->ignore_desync) {
pts -= base_pts;
if (pts > 0.0) { // Skip.
- ret = camu_audio_format_sec_to_bytes(fmt, pts);
+ ret = (ptrdiff_t)camu_audio_format_sec_to_bytes(fmt, pts);
ret = MIN(ret, have);
- al_log_info("audio_buffer", "Skipping %fs of audio (%zu bytes).", pts, ret);
+ al_log_info("audio_buffer", "Skipping %fs of audio (%zd bytes).", pts, ret);
ret = al_ring_buffer_discard(&buf->rb, ret);
have -= ret;
base_pts += camu_audio_format_bytes_to_sec(fmt, ret);
// Could go on to underrun.
} else if (pts < 0.0) { // Delay.
pts = -pts;
- ret = camu_audio_format_sec_to_bytes(fmt, pts);
+ ret = (ptrdiff_t)camu_audio_format_sec_to_bytes(fmt, pts);
ret = MIN(ret, req);
al_log_info("audio_buffer", "Delaying audio by %fs.", pts);
al_memset(data, 0, ret);
@@ -366,7 +360,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re
// enough for this request.
if (have < req) {
signal = have;
- al_log_debug("audio_buffer", "Flushed (signal: %zu).", signal);
+ al_log_debug("audio_buffer", "Flushed (signal: %zd).", signal);
buf->callback(buf->userdata, CAMU_BUFFER_EOF);
al_atomic_store(u8)(&buf->flow, SIGNALED, AL_ATOMIC_RELEASE);
}
@@ -377,7 +371,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re
// We hit an underrun because data wasn't coming in fast enough.
// An underrun can also happen in the audio output if read() (this function)
// takes too long. That isn't checked here.
- al_log_warn("audio_buffer", "Underrun (req: %zu, have: %zu).", req, have);
+ al_log_warn("audio_buffer", "Underrun (req: %zd, have: %zd).", req, have);
// If we have data by the next read(), try to skip ahead to maintain sync.
// This might exacerbate the underrun issue but an underrun is already
// unexpected behavior, trying to stay in sync comes first.
@@ -435,7 +429,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re
#else
if (flow == FLOWING) {
#endif
- ret = al_atomic_load(size_t)(&buf->uncork_at, AL_ATOMIC_RELAXED);
+ ret = al_atomic_load(ptrdiff_t)(&buf->uncork_at, AL_ATOMIC_RELAXED);
if (ret && have - req <= ret) {
buf->callback(buf->userdata, CAMU_BUFFER_UNCORK);
}
diff --git a/src/buffer/audio.h b/src/buffer/audio.h
index ca2d405..901becf 100644
--- a/src/buffer/audio.h
+++ b/src/buffer/audio.h
@@ -27,15 +27,15 @@ struct camu_audio_buffer {
struct camu_resampler *resampler;
u8 *data;
- size_t size;
+ ptrdiff_t size;
struct al_ring_buffer rb;
- struct { size_t min, buffered; } mark;
+ struct { ptrdiff_t min, buffered; } mark;
bool buffered;
atomic(u8) flow;
struct camu_peak_buffer peak;
- atomic(size_t) uncork_at;
+ atomic(ptrdiff_t) uncork_at;
struct {
f32 user;
@@ -46,7 +46,7 @@ struct camu_audio_buffer {
#ifdef CAMU_AUDIO_BUFFER_FADE
struct {
f32 volume;
- size_t offset;
+ ptrdiff_t offset;
} fade;
#endif
@@ -69,5 +69,5 @@ void camu_audio_buffer_push(struct camu_audio_buffer *buf, struct camu_codec_fra
void camu_audio_buffer_flush(struct camu_audio_buffer *buf);
void camu_audio_buffer_reset(struct camu_audio_buffer *buf);
void camu_audio_buffer_unpause(struct camu_audio_buffer *buf);
-size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t req);
+ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdiff_t req);
void camu_audio_buffer_free(struct camu_audio_buffer *buf);
diff --git a/src/buffer/common_internal.h b/src/buffer/common_internal.h
index e4cdd33..11caddc 100644
--- a/src/buffer/common_internal.h
+++ b/src/buffer/common_internal.h
@@ -1,5 +1,9 @@
#pragma once
+#include <al/types.h>
+
+#include "clock.h"
+
enum {
// Flowing.
FLOWING,
@@ -10,3 +14,9 @@ enum {
// Errored.
ERRORED
};
+
+static inline bool frame_is_late(struct camu_clock *clock, f64 base, f64 pts, f64 duration)
+{
+ if (base == -1.0) base = camu_clock_get_base_pts(clock);
+ return pts + duration < base;
+}
diff --git a/src/buffer/peak_buffer.c b/src/buffer/peak_buffer.c
index 9687a1f..c1fe254 100644
--- a/src/buffer/peak_buffer.c
+++ b/src/buffer/peak_buffer.c
@@ -2,20 +2,22 @@
// https://github.com/MusicPlayerDaemon/MPD/blob/c71e586c530e1d066efde7c2ca40c363f74100c7/src/util/PeakBuffer.cxx
-void camu_peak_buffer_init(struct camu_peak_buffer *buf, size_t size)
+// We use ptrdiff_t here instead of nn_buffer's size_t just to map better to the types in audio_buffer.
+
+void camu_peak_buffer_init(struct camu_peak_buffer *buf, ptrdiff_t size)
{
nn_buffer_init(&buf->buf);
- nn_buffer_ensure_space(&buf->buf, size);
+ nn_buffer_ensure_space(&buf->buf, (size_t)size);
}
-void camu_peak_buffer_push(struct camu_peak_buffer *buf, u8 *data, size_t size)
+void camu_peak_buffer_push(struct camu_peak_buffer *buf, u8 *data, ptrdiff_t size)
{
- nn_buffer_append(&buf->buf, data, size);
+ nn_buffer_append(&buf->buf, data, (size_t)size);
}
-size_t camu_peak_buffer_get_size(struct camu_peak_buffer *buf)
+ptrdiff_t camu_peak_buffer_get_size(struct camu_peak_buffer *buf)
{
- return nn_buffer_get_size(&buf->buf);
+ return (ptrdiff_t)nn_buffer_get_size(&buf->buf);
}
u8 *camu_peak_buffer_flush(struct camu_peak_buffer *buf)
diff --git a/src/buffer/peak_buffer.h b/src/buffer/peak_buffer.h
index 9bd3316..73465ec 100644
--- a/src/buffer/peak_buffer.h
+++ b/src/buffer/peak_buffer.h
@@ -7,8 +7,8 @@ struct camu_peak_buffer {
struct nn_buffer buf;
};
-void camu_peak_buffer_init(struct camu_peak_buffer *buf, size_t size);
-void camu_peak_buffer_push(struct camu_peak_buffer *buf, u8 *data, size_t size);
-size_t camu_peak_buffer_get_size(struct camu_peak_buffer *buf);
+void camu_peak_buffer_init(struct camu_peak_buffer *buf, ptrdiff_t size);
+void camu_peak_buffer_push(struct camu_peak_buffer *buf, u8 *data, ptrdiff_t size);
+ptrdiff_t camu_peak_buffer_get_size(struct camu_peak_buffer *buf);
u8 *camu_peak_buffer_flush(struct camu_peak_buffer *buf);
void camu_peak_buffer_free(struct camu_peak_buffer *buf);
diff --git a/src/buffer/video.c b/src/buffer/video.c
index 47c1ea9..01f317e 100644
--- a/src/buffer/video.c
+++ b/src/buffer/video.c
@@ -10,9 +10,9 @@
#endif
#endif
-#define BUFFER_MARK_LOW ((1.0 / 30.0) * 4)
+#define BUFFER_MARK_LOW ((1.0 / 30.0) * 6)
#define BUFFER_MARK_BUFFERED ((1.0 / 30.0) * 5)
-#define BUFFER_MARK_HIGH ((1.0 / 30.0) * 10)
+#define BUFFER_MARK_HIGH ((1.0 / 30.0) * 12)
#define BUFFER_MARK_RESET (BUFFER_MARK_HIGH * 2.0)
bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *clock)
@@ -46,11 +46,17 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code
struct camu_video_format *fmt = &buf->stream->video.fmt;
switch (stream->mode) {
case CAMU_NORMAL: {
- buf->single_frame = true;
camu_video_format_copy(&buf->fmt.in, fmt);
+
+ buf->single_frame = true;
+ buf->avg_frame_duration = 0.0;
+
const char *format_name = camu_pixel_format_name(fmt->format);
if (!format_name) format_name = "unknown";
- al_log_info("video_buffer", "Stream: %s (%dx%d) %s.", format_name, fmt->width, fmt->height, "IMAGE");
+
+ al_log_info("video_buffer", "Stream: %s (%dx%d) %s.",
+ format_name, fmt->width, fmt->height, "IMAGE");
+
break;
}
#ifdef CAMU_HAVE_FFMPEG
@@ -64,12 +70,16 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code
camu_video_format_copy(&buf->fmt.in, fmt);
buf->single_frame = stream->duration == 0 || frame_rate.den == 0;
- if (buf->single_frame) frame_rate = (AVRational){ 0, 1 };
buf->avg_frame_duration = buf->single_frame ? 0.0 : av_q2d(av_inv_q(frame_rate));
const char *format_name = av_get_pix_fmt_name(buf->fmt.in.format);
- al_log_info("video_buffer", "Stream: %s (%dx%d) %s %.2ffps.",
- format_name, fmt->width, fmt->height, buf->single_frame ? "IMAGE" : "VIDEO", av_q2d(frame_rate));
+ if (buf->single_frame) {
+ al_log_info("video_buffer", "Stream: %s (%dx%d) %s.",
+ format_name, fmt->width, fmt->height, "IMAGE");
+ } else {
+ al_log_info("video_buffer", "Stream: %s (%dx%d) %s %.3ffps.",
+ format_name, fmt->width, fmt->height, "VIDEO", av_q2d(frame_rate));
+ }
break;
}
@@ -129,13 +139,17 @@ static void after_push_internal(struct camu_video_buffer *buf)
if (!buf->buffered && (buf->single_frame || have >= BUFFER_MARK_BUFFERED)) {
// Preserve order of: flush -> callback -> set flow, for single frames.
- if (buf->single_frame) buf->queue->flush(buf->queue);
+ if (buf->single_frame) {
+ buf->queue->flush(buf->queue);
+ }
al_log_debug("video_buffer", "Buffered (mark: %.2fs).", have);
buf->callback(buf->userdata, CAMU_BUFFER_BUFFERED);
buf->buffered = true;
- if (buf->single_frame) al_atomic_store(u8)(&buf->flow, FLUSHED, AL_ATOMIC_RELAXED);
+ if (buf->single_frame) {
+ al_atomic_store(u8)(&buf->flow, FLUSHED, AL_ATOMIC_RELAXED);
+ }
}
if (have >= BUFFER_MARK_RESET) {
@@ -146,12 +160,6 @@ static void after_push_internal(struct camu_video_buffer *buf)
}
}
-static inline bool frame_is_late(struct camu_clock *clock, f64 base, f64 pts, f64 duration)
-{
- if (base == -1.0) base = camu_clock_get_base_pts(clock);
- return pts + duration < base;
-}
-
#ifdef CAMU_HAVE_FFMPEG
static bool push_av_frame_internal(struct camu_video_buffer *buf, AVFrame *frame)
{
@@ -248,6 +256,7 @@ bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out, bool *weig
al_atomic_store(f64)(&buf->pts, base, AL_ATOMIC_RELEASE);
}
}
+
u8 ret = buf->queue->read(buf->queue, base, out);
u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_ACQUIRE);
if (ret == CAMU_QUEUE_ERR) {