summaryrefslogtreecommitdiff
path: root/src/buffer
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer')
-rw-r--r--src/buffer/audio.c70
-rw-r--r--src/buffer/video.c18
-rw-r--r--src/buffer/video.h1
-rw-r--r--src/buffer/video_null.h8
4 files changed, 37 insertions, 60 deletions
diff --git a/src/buffer/audio.c b/src/buffer/audio.c
index e9ba16c..8bfed20 100644
--- a/src/buffer/audio.c
+++ b/src/buffer/audio.c
@@ -1,3 +1,4 @@
+#define AL_LOG_SECTION "audio_buffer"
#include <al/log.h>
#ifdef CAMU_HAVE_FFMPEG
@@ -59,12 +60,16 @@ bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *cl
bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_codec_stream *stream,
struct camu_mixer *mixer)
{
- camu_audio_format_copy(&buf->fmt.in, &stream->audio.fmt);
- camu_mixer_pick_format(mixer, &buf->fmt);
+ buf->stream = stream;
+
+ struct camu_audio_format *fmt = &stream->audio.fmt;
+ const char *format_name = camu_audio_format_name(fmt->format);
+ info("Stream: %s (%dch) %dHz.", format_name, fmt->channel_count, fmt->sample_rate);
struct camu_audio_format *in = &buf->fmt.in;
struct camu_audio_format *req = &buf->fmt.req;
-
+ camu_audio_format_copy(in, fmt);
+ camu_mixer_pick_format(mixer, &buf->fmt);
buf->fmt.resampler_needed = !camu_resampler_format_matches(&buf->fmt);
if (buf->fmt.resampler_needed) {
#ifdef CAMU_HAVE_FFMPEG
@@ -76,12 +81,10 @@ bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_code
#else
return false;
#endif
+ const char *req_format_name = camu_audio_format_name(req->format);
+ info("Resampling to: %s (%dch) %dHz.", req_format_name, req->channel_count, req->sample_rate);
}
- al_log_info("audio_buffer", "Stream: %s (%dch) %dHz -> %s (%dch) %dHz.",
- camu_audio_format_name(in->format), in->channel_count, in->sample_rate,
- camu_audio_format_name(req->format), req->channel_count, req->sample_rate);
-
buf->size = (ptrdiff_t)camu_audio_format_sec_to_bytes(req, BUFFER_SIZE);
buf->data = (u8 *)al_malloc(buf->size);
al_ring_buffer_init(&buf->rb, buf->data, buf->size);
@@ -90,8 +93,6 @@ bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_code
buf->mark.buffered = (ptrdiff_t)camu_audio_format_sec_to_bytes(req, BUFFER_MARK_BUFFERED);
camu_peak_buffer_init(&buf->peak, KB(16));
- buf->stream = stream;
-
return true;
}
@@ -150,7 +151,7 @@ static bool push_internal(struct camu_audio_buffer *buf, f64 pts, u8 **data, s32
// The maximum space is buf->size - 1.
ptrdiff_t space = al_ring_buffer_space(&buf->rb);
if (!buf->buffered && (buf->size - 1) - space >= buf->mark.buffered) {
- al_log_debug("audio_buffer", "Buffered (mark: %.1fKB).", buf->mark.buffered / 1024.0);
+ debug("Buffered (mark: %.1fKB).", buf->mark.buffered / 1024.0);
buf->callback(buf->userdata, CAMU_BUFFER_BUFFERED);
buf->buffered = true;
}
@@ -163,7 +164,7 @@ static bool push_internal(struct camu_audio_buffer *buf, f64 pts, u8 **data, s32
peak += have;
if (peak >= buf->mark.min) {
// If this happens the writer of this buffer is taking way too long to stop.
- al_log_warn("audio_buffer", "Overrun likely, discarding peak buffer (audio will desync).");
+ warn("Overrun likely, discarding peak buffer (audio will be desynced).");
camu_peak_buffer_flush(&buf->peak);
peak = 0;
}
@@ -199,7 +200,6 @@ static void push_av_frame_internal(struct camu_audio_buffer *buf, AVFrame *frame
void camu_audio_buffer_push(struct camu_audio_buffer *buf, struct camu_codec_frame *frame)
{
al_assert(al_atomic_load(u8)(&buf->flow, AL_ATOMIC_RELAXED) == FLOWING);
-
switch (frame->mode) {
case CAMU_NORMAL: {
s32 sample_count = frame->audio.sample_count;
@@ -215,25 +215,21 @@ void camu_audio_buffer_push(struct camu_audio_buffer *buf, struct camu_codec_fra
}
#endif
}
-
al_free(frame);
}
// flush() always comes from the same thread as push().
void camu_audio_buffer_flush(struct camu_audio_buffer *buf)
{
- al_log_debug("audio_buffer", "Flush requested.");
-
+ debug("Flush requested.");
if (!push_internal(buf, 0.0, NULL, 0)) {
- al_log_debug("audio_buffer", "Buffer filled by flush.");
+ debug("Buffer filled by flush.");
}
-
if (!buf->buffered) {
- al_log_debug("audio_buffer", "Buffered (flush).");
+ debug("Buffered (flush).");
buf->callback(buf->userdata, CAMU_BUFFER_BUFFERED);
buf->buffered = true;
}
-
al_atomic_store(u8)(&buf->flow, FLUSHED, AL_ATOMIC_RELAXED);
}
@@ -305,16 +301,14 @@ ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdif
if (al_atomic_load(u32)(&buf->volume.set, AL_ATOMIC_ACQUIRE) > 0) {
buf->volume.user = al_atomic_load(f32)(&buf->volume.queued, AL_ATOMIC_RELAXED);
#ifdef CAMU_AUDIO_BUFFER_FADE
- if (buf->fade.volume == -1.f) {
- buf->fade.volume = buf->volume.user;
- }
+ if (buf->fade.volume == -1.f) buf->fade.volume = buf->volume.user;
#endif
al_atomic_sub(u32)(&buf->volume.set, 1, AL_ATOMIC_RELEASE);
}
if (!buf->ignore_desync && al_atomic_load(u32)(&buf->unpause, AL_ATOMIC_ACQUIRE) > 0) {
// Queuing multiple resyncs before resuming the stream will cause pops!
- al_log_info("audio_buffer", "Forcing resync.");
+ info("Forcing resync.");
buf->pause = PAUSE_PAUSED;
al_atomic_sub(u32)(&buf->unpause, 1, AL_ATOMIC_RELEASE);
}
@@ -329,14 +323,14 @@ ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdif
#endif
// Unpause and possibly attempt syncing to the clock.
- // PAUSE_PAUSED signifies that the last read was silence, meaning we
- // can skip around in the buffer without worrying about pops.
+ // PAUSE_PAUSED signifies that the last read was silence, meaning we can skip around
+ // in the buffer without worrying about pops.
if (UNLIKELY(buf->pause == PAUSE_PAUSED)) {
if (!buf->ignore_desync) {
pts -= base_pts;
if (pts > 0.0) { // Skip.
ret = MIN((ptrdiff_t)camu_audio_format_sec_to_bytes(fmt, pts), have);
- al_log_info("audio_buffer", "Skipping %fs of audio (%zd bytes).", pts, ret);
+ info("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);
@@ -345,7 +339,7 @@ ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdif
pts = -pts;
ret = MIN((ptrdiff_t)camu_audio_format_sec_to_bytes(fmt, pts), req);
if (!buf->logged_delay) {
- al_log_info("audio_buffer", "Delaying audio by %fs.", pts);
+ info("Delaying audio by %fs.", pts);
buf->logged_delay = true;
}
al_memset(data, 0, ret);
@@ -374,7 +368,7 @@ ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdif
// enough for this request.
if (have < req) {
signal = have;
- al_log_debug("audio_buffer", "Flushed (signal: %zd).", signal);
+ debug("Flushed (signal: %zd).", signal);
buf->callback(buf->userdata, CAMU_BUFFER_EOF);
al_atomic_store(u8)(&buf->flow, SIGNALED, AL_ATOMIC_RELEASE);
}
@@ -385,7 +379,7 @@ ptrdiff_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, ptrdif
// 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: %zd, have: %zd).", req, have);
+ warn("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.
@@ -414,25 +408,17 @@ 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);
- } else if (buf->fade.volume < buf->volume.user) {
+ 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);
}
-
if (step != 0.f || buf->fade.volume != 1.f) {
- if (buf->volume.user > 1.f) {
- // Only adjust the step if it's an increase to avoid drawn out
- // fades if the volume is low.
- step *= buf->volume.user;
- }
- step *= MAX(buf->fade.volume, FADE_MIN);
buf->fade.volume = apply_volume(data, req, fmt, buf->fade.volume, buf->volume.user, step);
}
#else
- if (buf->volume.user != 1.f) {
- apply_volume(data, req, fmt, buf->volume.user, 0.f, 0.f);
- }
+ if (buf->volume.user != 1.f) apply_volume(data, req, fmt, buf->volume.user, 0.f, 0.f);
#endif
}
diff --git a/src/buffer/video.c b/src/buffer/video.c
index ed56ff8..54d83af 100644
--- a/src/buffer/video.c
+++ b/src/buffer/video.c
@@ -50,7 +50,6 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code
switch (stream->mode) {
case CAMU_NORMAL: {
buf->single_frame = true;
- buf->avg_frame_duration = 0.0;
info("Stream: %s (%ux%u) IMAGE.", format_name, fmt->width, fmt->height);
break;
}
@@ -58,10 +57,10 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code
case CAMU_FFMPEG_COMPAT: {
AVRational frame_rate = stream->av.stream->avg_frame_rate;
buf->single_frame = stream->duration == 0 || frame_rate.den == 0;
- buf->avg_frame_duration = frame_rate.den > 0 ? av_q2d(av_inv_q(frame_rate)) : 0.0;
if (buf->single_frame) {
info("Stream: %s (%ux%u) IMAGE.", format_name, fmt->width, fmt->height);
} else {
+ buf->avg_frame_duration = (frame_rate.den > 0) ? av_q2d(av_inv_q(frame_rate)) : 0.0;
info("Stream: %s (%ux%u) VIDEO %.3ffps.", format_name, fmt->width, fmt->height, av_q2d(frame_rate));
}
break;
@@ -77,17 +76,18 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code
if (fmt->width > 0 && fmt->height > 0 &&
(fmt->format != CAMU_PIXEL_FORMAT_RGBA && fmt->format != CAMU_PIXEL_FORMAT_RGB)) {
buf->fmt.scaler_needed = true;
-#ifndef CAMU_HAVE_FFMPEG
- return false;
-#endif
req->width = fmt->width;
req->height = fmt->height;
req->format = CAMU_PIXEL_FORMAT_RGBA;
+#ifdef CAMU_HAVE_FFMPEG
buf->scaler = camu_ff_scaler_create();
if (!buf->scaler->init(buf->scaler, &buf->fmt)) {
// Scaler will be freed in video_buffer_free().
return false;
}
+#else
+ return false;
+#endif
const char *req_format_name = camu_pixel_format_name(req->format);
info("Scaling to: %s (%ux%u).", req_format_name, req->width, req->height);
} else {
@@ -110,11 +110,6 @@ void camu_video_buffer_set_latency(struct camu_video_buffer *buf, s32 frames)
buf->latency = frames * buf->avg_frame_duration;
}
-bool camu_video_buffer_is_single_frame(struct camu_video_buffer *buf)
-{
- return buf->single_frame;
-}
-
static void after_push_internal(struct camu_video_buffer *buf)
{
s32 count = buf->queue->count(buf->queue);
@@ -205,9 +200,10 @@ void camu_video_buffer_flush(struct camu_video_buffer *buf)
buf->queue->flush(buf->queue);
if (!buf->buffered) {
s32 count = buf->queue->count(buf->queue);
+ f64 have = count * buf->avg_frame_duration;
buf->buffered = true;
buf->buffered_with_one_frame = count == 1;
- debug("Buffered (flush).");
+ debug("Buffered (mark: %.2fs).", have);
buf->callback(buf->userdata, CAMU_BUFFER_BUFFERED);
}
}
diff --git a/src/buffer/video.h b/src/buffer/video.h
index 401fa48..5bdf267 100644
--- a/src/buffer/video.h
+++ b/src/buffer/video.h
@@ -51,7 +51,6 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code
struct camu_renderer *renderer);
bool camu_video_buffer_configure_subtitles(struct camu_video_buffer *buf, struct camu_codec_stream *stream);
void camu_video_buffer_set_latency(struct camu_video_buffer *buf, s32 frames);
-bool camu_video_buffer_is_single_frame(struct camu_video_buffer *buf);
void camu_video_buffer_push(struct camu_video_buffer *buf, struct camu_codec_frame *frame);
void camu_video_buffer_push_subtitle(struct camu_video_buffer *buf, struct camu_codec_packet *packet);
void camu_video_buffer_flush(struct camu_video_buffer *buf);
diff --git a/src/buffer/video_null.h b/src/buffer/video_null.h
index 69da85f..8423b7c 100644
--- a/src/buffer/video_null.h
+++ b/src/buffer/video_null.h
@@ -7,6 +7,7 @@
#include "clock.h"
struct camu_video_buffer {
+ bool single_frame;
f64 avg_frame_duration;
#ifdef CAMU_SCREEN_THREADED
atomic(u8) ref;
@@ -25,6 +26,7 @@ AL_UNUSED_FUNCTION_PUSH
static bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *clock)
{
(void)clock;
+ buf->single_frame = false;
buf->avg_frame_duration = 0.0;
#ifdef CAMU_SCREEN_THREADED
al_atomic_store(u8)(&buf->ref, 0, AL_ATOMIC_RELAXED);
@@ -54,12 +56,6 @@ static void camu_video_buffer_set_latency(struct camu_video_buffer *buf, s32 fra
(void)frames;
}
-static bool camu_video_buffer_is_single_frame(struct camu_video_buffer *buf)
-{
- (void)buf;
- return false;
-}
-
static void camu_video_buffer_push(struct camu_video_buffer *buf, struct camu_codec_frame *frame)
{
(void)buf;