diff options
Diffstat (limited to 'src/buffer')
| -rw-r--r-- | src/buffer/audio.c | 84 | ||||
| -rw-r--r-- | src/buffer/audio.h | 10 | ||||
| -rw-r--r-- | src/buffer/frame_queue.h | 4 | ||||
| -rw-r--r-- | src/buffer/video.c | 88 | ||||
| -rw-r--r-- | src/buffer/video.h | 14 |
5 files changed, 121 insertions, 79 deletions
diff --git a/src/buffer/audio.c b/src/buffer/audio.c index 3abae42..5058154 100644 --- a/src/buffer/audio.c +++ b/src/buffer/audio.c @@ -9,9 +9,9 @@ #include "common_internal.h" #include "volume.h" -#define BUFFER_SIZE (9 * 1000000L) -#define BUFFER_MARK_MIN (4.3 * 1000000L) // Must be a most half of the buffer size. -#define BUFFER_MARK_BUFFERED (4.0 * 1000000L) +#define BUFFER_SIZE 9.0 +#define BUFFER_MARK_MIN 4.3 // Must be a most half of the buffer size. +#define BUFFER_MARK_BUFFERED 4.0 #ifdef CAMU_AUDIO_BUFFER_FADE #define FADE_STEP(fmt) (1.f / (fmt)->sample_rate) @@ -27,7 +27,7 @@ enum { static void reset_buffer_state(struct camu_audio_buffer *buf) { - buf->pts = -1.0; + al_atomic_store(f64)(&buf->pts, -1.0, AL_ATOMIC_RELAXED); buf->pause = PAUSE_PAUSED; al_atomic_store(s32)(&buf->unpause, 0, AL_ATOMIC_RELAXED); al_atomic_store(s32)(&buf->volume.set, 0, AL_ATOMIC_RELAXED); @@ -40,11 +40,9 @@ static void reset_buffer_state(struct camu_audio_buffer *buf) al_atomic_store(size_t)(&buf->uncork_at, 0, AL_ATOMIC_RELAXED); } -bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *clock, - struct camu_mixer *mixer) +bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *clock) { buf->clock = clock; - buf->mixer = mixer; reset_buffer_state(buf); buf->ignore_desync = false; buf->latency = 0.0; @@ -54,10 +52,11 @@ bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *cl return true; } -bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_codec_stream *stream) +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(buf->mixer, &buf->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 +75,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_usec_to_bytes(&buf->fmt.req, BUFFER_SIZE); + buf->size = 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_usec_to_bytes(&buf->fmt.req, BUFFER_MARK_MIN); - buf->mark.buffered = camu_audio_format_usec_to_bytes(&buf->fmt.req, BUFFER_MARK_BUFFERED); + 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); camu_peak_buffer_init(&buf->peak, 1024 * 16); buf->stream = stream; @@ -144,6 +143,16 @@ static bool push_internal(struct camu_audio_buffer *buf, u8 *data, s32 sample_co return true; } +static bool frame_is_late(struct camu_audio_buffer *buf, f64 pts, f64 duration) +{ + f64 base = al_atomic_load(f64)(&buf->pts, AL_ATOMIC_ACQUIRE); + if (base == -1.0) { + base = camu_clock_get_base_pts(buf->clock); + al_atomic_store(f64)(&buf->pts, base, AL_ATOMIC_RELEASE); + } + return pts + duration < base; +} + #ifdef CAMU_HAVE_FFMPEG static void push_av_frame_internal(struct camu_audio_buffer *buf, AVFrame *frame) { @@ -151,8 +160,7 @@ static void push_av_frame_internal(struct camu_audio_buffer *buf, AVFrame *frame AVStream *stream = buf->stream->av.stream; f64 pts = frame->best_effort_timestamp * av_q2d(stream->time_base); f64 duration = camu_audio_format_samples_to_sec(&buf->fmt.in, sample_count); - if (pts + duration >= camu_clock_get_base_pts(buf->clock)) { - if (buf->pts == -1.0) buf->pts = pts; + if (!frame_is_late(buf, pts, duration)) { u8 **data = frame->data; if (buf->fmt.resampler_needed) { sample_count = buf->resamp->convert(buf->resamp, (const u8 **)data, sample_count); @@ -173,9 +181,8 @@ void camu_audio_buffer_push(struct camu_audio_buffer *buf, struct camu_codec_fra s32 sample_count = frame->audio.sample_count; f64 pts = frame->pts; f64 duration = camu_audio_format_samples_to_sec(&buf->fmt.in, sample_count); - if (pts + duration >= camu_clock_get_base_pts(buf->clock)) { - if (buf->pts == -1.0) buf->pts = pts; - u8 *store[AV_NUM_DATA_POINTERS] = { 0 }; + if (!frame_is_late(buf, pts, duration)) { + u8 *store[CAMU_NUM_DATA_POINTERS] = { 0 }; store[0] = frame->data; u8 **data = store; if (buf->fmt.resampler_needed) { @@ -201,17 +208,6 @@ void camu_audio_buffer_unpause(struct camu_audio_buffer *buf) al_atomic_add(s32)(&buf->unpause, 1, AL_ATOMIC_RELAXED); } -// Not thread-safe, must be called while the buffer is not being read from or written to. -void camu_audio_buffer_reset(struct camu_audio_buffer *buf) -{ - reset_buffer_state(buf); - al_ring_buffer_reset(&buf->rb); - camu_peak_buffer_flush(&buf->peak); - if (buf->fmt.resampler_needed) { - buf->resamp->flush(buf->resamp); - } -} - // flush() always comes from the same thread as push(). void camu_audio_buffer_flush(struct camu_audio_buffer *buf) { @@ -233,18 +229,29 @@ void camu_audio_buffer_flush(struct camu_audio_buffer *buf) al_log_debug("audio_buffer", "Flush requested."); } +// Not thread-safe, must be called while the buffer is not being read from or written to. +void camu_audio_buffer_reset(struct camu_audio_buffer *buf) +{ + reset_buffer_state(buf); + al_ring_buffer_reset(&buf->rb); + camu_peak_buffer_flush(&buf->peak); + if (buf->fmt.resampler_needed) { + buf->resamp->flush(buf->resamp); + } +} + +static void increment_pts(struct camu_audio_buffer *buf, f64 amount, f64 *base) +{ + *base += amount; + al_atomic_store(f64)(&buf->pts, *base, AL_ATOMIC_RELEASE); +} + #define NOT_PAUSED(pause) (pause != PAUSE_PAUSED) // 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) { - u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_ACQUIRE); - if (flow == SIGNALED || camu_clock_is_ended(buf->clock)) { - buf->callback(buf->userdata, CAMU_BUFFER_EOF); - return 0; - } - 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); #ifdef CAMU_AUDIO_BUFFER_FADE @@ -287,6 +294,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re al_atomic_sub(s32)(&buf->unpause, 1, AL_ATOMIC_RELEASE); } + f64 base = al_atomic_load(f64)(&buf->pts, AL_ATOMIC_ACQUIRE); f64 pts = camu_clock_get_pts(buf->clock, buf->latency); size_t ret, signal = req; size_t have = al_ring_buffer_occupied(&buf->rb); @@ -296,7 +304,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re else have -= buf->fade.offset; if (buf->pause != PAUSE_FADING && buf->pause != PAUSE_PLAYING) { #endif - pts -= buf->pts; + pts -= base; // Attempt syncing to the clock. // For this to work the mixer must report a reasonably accurate value for latency. if (UNLIKELY(!buf->ignore_desync && buf->pause == PAUSE_PAUSED)) { @@ -306,7 +314,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re al_log_info("audio_buffer", "Skipping %fs of audio (%zu bytes).", pts, ret); ret = al_ring_buffer_discard(&buf->rb, ret); have -= ret; - buf->pts += camu_audio_format_bytes_to_sec(&buf->fmt.req, ret); + increment_pts(buf, camu_audio_format_bytes_to_sec(&buf->fmt.req, ret), &base); // Could go on to underrun. } else if (pts < 0.0) { // Delay. pts = -pts; @@ -325,6 +333,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re } #endif + u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_ACQUIRE); if (have < req) { // We don't have enough data to fulfill our request. if (flow == FLUSHED) { // Stream is flushed. // Check peak buffer for any remaining data. @@ -375,7 +384,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re // Read as much as we determined we can. ret = al_ring_buffer_read(&buf->rb, data, req); al_assert(ret == req); - buf->pts += camu_audio_format_bytes_to_sec(&buf->fmt.req, ret); + increment_pts(buf, camu_audio_format_bytes_to_sec(&buf->fmt.req, ret), &base); #ifdef CAMU_AUDIO_BUFFER_FADE } f32 step = 0.f; @@ -386,6 +395,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re } if (step != 0.f || buf->fade.volume != 1.f) { if (buf->volume.user > 1.f) { + // Only adjust step if it's an increase. step *= buf->volume.user; } buf->fade.volume = apply_volume(data, req, &buf->fmt.req, buf->fade.volume, buf->volume.user, step); diff --git a/src/buffer/audio.h b/src/buffer/audio.h index 1d49448..b4d7594 100644 --- a/src/buffer/audio.h +++ b/src/buffer/audio.h @@ -13,9 +13,8 @@ struct camu_audio_buffer { struct camu_codec_stream *stream; - struct camu_mixer *mixer; - f64 pts; + atomic(f64) pts; u8 pause; atomic(s32) unpause; struct camu_clock *clock; @@ -57,13 +56,14 @@ struct camu_audio_buffer { void *userdata; }; -bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *clock, struct camu_mixer *mixer); -bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_codec_stream *stream); +bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *clock); +bool camu_audio_buffer_configure(struct camu_audio_buffer *buf, struct camu_codec_stream *stream, + struct camu_mixer *mixer); void camu_audio_buffer_set_volume(struct camu_audio_buffer *buf, f32 volume); void camu_audio_buffer_set_latency(struct camu_audio_buffer *buf, f64 latency); void camu_audio_buffer_push(struct camu_audio_buffer *buf, struct camu_codec_frame *frame); void camu_audio_buffer_unpause(struct camu_audio_buffer *buf); -void camu_audio_buffer_reset(struct camu_audio_buffer *buf); void camu_audio_buffer_flush(struct camu_audio_buffer *buf); +void camu_audio_buffer_reset(struct camu_audio_buffer *buf); size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t req); void camu_audio_buffer_free(struct camu_audio_buffer *buf); diff --git a/src/buffer/frame_queue.h b/src/buffer/frame_queue.h index 0175668..f670ded 100644 --- a/src/buffer/frame_queue.h +++ b/src/buffer/frame_queue.h @@ -5,6 +5,7 @@ #endif #include "../codec/codec.h" +#include "../buffer/video.h" enum { CAMU_QUEUE_OK = 0, @@ -14,9 +15,12 @@ enum { }; struct camu_frame_queue { + struct camu_video_buffer *buf; void (*push)(struct camu_frame_queue *, struct camu_codec_frame *, f64); #ifdef CAMU_HAVE_FFMPEG void (*push_av_frame)(struct camu_frame_queue *, AVFrame *, f64); + void (*configure_subtitles)(struct camu_frame_queue *, s32, s32, AVCodecParameters *); + void (*push_subtitle)(struct camu_frame_queue *, AVPacket *); #endif void (*flush)(struct camu_frame_queue *); s32 (*count)(struct camu_frame_queue *); diff --git a/src/buffer/video.c b/src/buffer/video.c index a8b35c6..b528141 100644 --- a/src/buffer/video.c +++ b/src/buffer/video.c @@ -15,14 +15,15 @@ #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, struct camu_renderer *renderer) +bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *clock) { buf->clock = clock; buf->latency = 0.0; - buf->pts = -1.0; + al_atomic_store(f64)(&buf->pts, -1.0, AL_ATOMIC_RELAXED); // Defaulting single_frame to true can simplify non-configured buffers in sink. buf->single_frame = true; - buf->queue = renderer->create_queue(renderer); + buf->avg_frame_duration = 0.0; + buf->queue = NULL; buf->buffered = false; al_atomic_store(u8)(&buf->flow, FLOWING, AL_ATOMIC_RELAXED); #ifdef CAMU_SCREEN_THREADED @@ -32,27 +33,23 @@ bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *cl return true; } -bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_codec_stream *stream) +bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_codec_stream *stream, + struct camu_renderer *renderer) { buf->stream = stream; + buf->queue = renderer->create_queue(renderer); + buf->queue->buf = buf; struct camu_video_format *fmt = &buf->stream->video.fmt; switch (stream->mode) { case CAMU_NORMAL: { 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); - 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 case CAMU_FFMPEG_COMPAT: { AVCodecParameters *codecpar = stream->av.stream->codecpar; - s64 duration = stream->av.stream->duration; AVRational frame_rate = stream->av.stream->avg_frame_rate; fmt->width = codecpar->width; @@ -60,7 +57,7 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code fmt->format = codecpar->format; camu_video_format_copy(&buf->fmt.in, fmt); - buf->single_frame = duration == 0 || frame_rate.den == 0; + 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)); @@ -129,25 +126,33 @@ static void after_push_internal(struct camu_video_buffer *buf) static bool push_av_frame_internal(struct camu_video_buffer *buf, AVFrame *frame) { f64 pts = 0.0; + f64 base = al_atomic_load(f64)(&buf->pts, AL_ATOMIC_ACQUIRE); if (!buf->single_frame) { AVStream *stream = buf->stream->av.stream; pts = frame->best_effort_timestamp * av_q2d(stream->time_base); - if (pts + buf->avg_frame_duration < camu_clock_get_base_pts(buf->clock)) { + // If buf->pts = -1.0, this is the first frame pushed either on + // a new stream or after a reset(). Meaning, we can safely set buf->pts + // from this thread. + if (base == -1.0) { + base = camu_clock_get_base_pts(buf->clock); + al_atomic_store(f64)(&buf->pts, base, AL_ATOMIC_RELEASE); + } + if (pts + buf->avg_frame_duration < base) { av_frame_free(&frame); return false; } + } else if (base == -1.0) { + al_atomic_store(f64)(&buf->pts, 0.0, AL_ATOMIC_RELEASE); } - if (buf->pts == -1.0) buf->pts = pts; #ifdef CAMU_VIDEO_BUFFER_FORCE_SCALER if (buf->fmt.scaler_needed) { if (!buf->scale->scale(buf->scale, (const u8 **)frame->data, frame->linesize)) { return false; } av_frame_free(&frame); - frame = av_frame_clone(buf->scale->get_frame(buf->scale)); + frame = av_frame_clone(buf->scale->get_frame(buf->scale)->av.frame); } #endif - if (frame) frame->opaque = buf; buf->queue->push_av_frame(buf->queue, frame, pts); return true; } @@ -161,9 +166,14 @@ void camu_video_buffer_push(struct camu_video_buffer *buf, struct camu_codec_fra return; } switch (frame->mode) { - case CAMU_NORMAL: + case CAMU_NORMAL: { + f64 base = al_atomic_load(f64)(&buf->pts, AL_ATOMIC_ACQUIRE); + if (base == -1.0) { + al_atomic_store(f64)(&buf->pts, 0.0, AL_ATOMIC_RELEASE); + } buf->queue->push(buf->queue, frame, 0.0); break; + } #ifdef CAMU_HAVE_FFMPEG case CAMU_FFMPEG_COMPAT: { bool pushed = push_av_frame_internal(buf, frame->av.frame); @@ -176,15 +186,19 @@ void camu_video_buffer_push(struct camu_video_buffer *buf, struct camu_codec_fra after_push_internal(buf); } -// Not thread-safe, must be called while the buffer is not being read from or written to. -void camu_video_buffer_reset(struct camu_video_buffer *buf) +#ifdef CAMU_HAVE_FFMPEG +void camu_video_buffer_configure_subtitles(struct camu_video_buffer *buf, AVCodecParameters *codecpar) { - buf->pts = -1.0; - buf->queue->reset(buf->queue); - buf->buffered = false; - al_atomic_store(u8)(&buf->flow, FLOWING, AL_ATOMIC_RELAXED); + struct camu_video_format *fmt = &buf->stream->video.fmt; + buf->queue->configure_subtitles(buf->queue, fmt->width, fmt->height, codecpar); } +void camu_video_buffer_push_subtitle(struct camu_video_buffer *buf, AVPacket *pkt) +{ + buf->queue->push_subtitle(buf->queue, pkt); +} +#endif + // flush() always comes from the same thread as push(). void camu_video_buffer_flush(struct camu_video_buffer *buf) { @@ -198,18 +212,28 @@ void camu_video_buffer_flush(struct camu_video_buffer *buf) al_atomic_store(u8)(&buf->flow, FLUSHED, AL_ATOMIC_RELAXED); } +// Not thread-safe, must be called while the buffer is not being read from or written to. +void camu_video_buffer_reset(struct camu_video_buffer *buf) +{ + al_atomic_store(f64)(&buf->pts, -1.0, AL_ATOMIC_RELAXED); + if (buf->queue) buf->queue->reset(buf->queue); + buf->buffered = false; + al_atomic_store(u8)(&buf->flow, FLOWING, AL_ATOMIC_RELAXED); +} + bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out) { - u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_ACQUIRE); + f64 base = 0.0; if (!buf->single_frame) { - if (flow == SIGNALED || camu_clock_is_ended(buf->clock)) { - buf->callback(buf->userdata, CAMU_BUFFER_EOF); - return false; - } + base = al_atomic_load(f64)(&buf->pts, AL_ATOMIC_ACQUIRE); f64 pts = camu_clock_get_pts(buf->clock, buf->latency); - if (pts > buf->pts) buf->pts = pts; + if (pts > base) { + base = pts; + al_atomic_store(f64)(&buf->pts, base, AL_ATOMIC_RELEASE); + } } - u8 ret = buf->queue->read(buf->queue, buf->pts, out); + u8 ret = buf->queue->read(buf->queue, base, out); + u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_ACQUIRE); if (flow == FLUSHED && (ret == CAMU_QUEUE_EOF || (buf->single_frame && ret == CAMU_QUEUE_OK))) { buf->callback(buf->userdata, CAMU_BUFFER_EOF); al_atomic_store(u8)(&buf->flow, SIGNALED, AL_ATOMIC_RELEASE); @@ -228,5 +252,5 @@ void camu_video_buffer_free(struct camu_video_buffer *buf) #ifdef CAMU_VIDEO_BUFFER_FORCE_SCALER if (buf->fmt.scaler_needed) buf->scale->free(&buf->scale); #endif - buf->queue->free(&buf->queue); + if (buf->queue) buf->queue->free(&buf->queue); } diff --git a/src/buffer/video.h b/src/buffer/video.h index 0b48361..fd7ec9f 100644 --- a/src/buffer/video.h +++ b/src/buffer/video.h @@ -6,7 +6,6 @@ #include "../codec/codec.h" #include "../render/renderer.h" -#include "../screen/screen.h" #include "../screen/view.h" #include "clock.h" @@ -17,7 +16,7 @@ struct camu_video_buffer { struct camu_clock *clock; f64 latency; - f64 pts; + atomic(f64) pts; bool single_frame; f64 avg_frame_duration; @@ -42,12 +41,17 @@ struct camu_video_buffer { void *userdata; }; -bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *clock, struct camu_renderer *renderer); -bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_codec_stream *stream); +bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *clock); +bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_codec_stream *stream, + struct camu_renderer *renderer); 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_reset(struct camu_video_buffer *buf); +#ifdef CAMU_HAVE_FFMPEG +void camu_video_buffer_configure_subtitles(struct camu_video_buffer *buf, AVCodecParameters *codecpar); +void camu_video_buffer_push_subtitle(struct camu_video_buffer *buf, AVPacket *pkt); +#endif void camu_video_buffer_flush(struct camu_video_buffer *buf); +void camu_video_buffer_reset(struct camu_video_buffer *buf); bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out); void camu_video_buffer_free(struct camu_video_buffer *buf); |