mpv/misc/ring.c

132 lines
3.4 KiB
C

/*
* This file is part of mpv.
* Copyright (c) 2012 wm4
* Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <inttypes.h>
#include <assert.h>
#include "common/common.h"
#include "mpv_talloc.h"
#include "osdep/atomic.h"
#include "ring.h"
struct mp_ring {
uint8_t *buffer;
/* Positions of the first readable/writeable chunks. Do not read these
* fields. Use the atomic private accessors `mp_ring_get_wpos`
* and `mp_ring_get_rpos`. */
atomic_ullong rpos, wpos;
};
static unsigned long long mp_ring_get_wpos(struct mp_ring *buffer)
{
return atomic_load(&buffer->wpos);
}
static unsigned long long mp_ring_get_rpos(struct mp_ring *buffer)
{
return atomic_load(&buffer->rpos);
}
struct mp_ring *mp_ring_new(void *talloc_ctx, int size)
{
struct mp_ring *ringbuffer =
talloc_zero(talloc_ctx, struct mp_ring);
*ringbuffer = (struct mp_ring) {
.buffer = talloc_size(talloc_ctx, size),
};
return ringbuffer;
}
int mp_ring_read(struct mp_ring *buffer, unsigned char *dest, int len)
{
int size = mp_ring_size(buffer);
int buffered = mp_ring_buffered(buffer);
int read_len = MPMIN(len, buffered);
int read_ptr = mp_ring_get_rpos(buffer) % size;
int len1 = MPMIN(size - read_ptr, read_len);
int len2 = read_len - len1;
if (dest) {
memcpy(dest, buffer->buffer + read_ptr, len1);
memcpy(dest + len1, buffer->buffer, len2);
}
atomic_fetch_add(&buffer->rpos, read_len);
return read_len;
}
int mp_ring_drain(struct mp_ring *buffer, int len)
{
return mp_ring_read(buffer, NULL, len);
}
int mp_ring_write(struct mp_ring *buffer, unsigned char *src, int len)
{
int size = mp_ring_size(buffer);
int free = mp_ring_available(buffer);
int write_len = MPMIN(len, free);
int write_ptr = mp_ring_get_wpos(buffer) % size;
int len1 = MPMIN(size - write_ptr, write_len);
int len2 = write_len - len1;
memcpy(buffer->buffer + write_ptr, src, len1);
memcpy(buffer->buffer, src + len1, len2);
atomic_fetch_add(&buffer->wpos, write_len);
return write_len;
}
void mp_ring_reset(struct mp_ring *buffer)
{
atomic_store(&buffer->wpos, 0);
atomic_store(&buffer->rpos, 0);
}
int mp_ring_available(struct mp_ring *buffer)
{
return mp_ring_size(buffer) - mp_ring_buffered(buffer);
}
int mp_ring_size(struct mp_ring *buffer)
{
return talloc_get_size(buffer->buffer);
}
int mp_ring_buffered(struct mp_ring *buffer)
{
return (mp_ring_get_wpos(buffer) - mp_ring_get_rpos(buffer));
}
char *mp_ring_repr(struct mp_ring *buffer, void *talloc_ctx)
{
return talloc_asprintf(
talloc_ctx,
"Ringbuffer { .size = %dB, .buffered = %dB, .available = %dB }",
mp_ring_size(buffer),
mp_ring_buffered(buffer),
mp_ring_available(buffer));
}