Files
2026-08-24 10:03:24 +08:00

277 lines
7.3 KiB
C

/*
* Copyright (C) 2014-2024 Amlogic, Inc. All rights reserved.
*
* All information contained herein is Amlogic confidential.
*
* This software is provided to you pursuant to Software License Agreement
* (SLA) with Amlogic Inc ("Amlogic"). This software may be used
* only in accordance with the terms of this agreement.
*
* Redistribution and use in source and binary forms, with or without
* modification is strictly prohibited without prior written permission from
* Amlogic.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "ringbuffer"
#include "ringbuffer.h"
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "SubtitleLog.h"
// Handle to a buffer structure
// Create with buffer_create(), destroy with buffer_free()
typedef struct {
char *buffer;
int buffer_size;
int read_pos;
int write_pos;
int read_avail;
int write_avail;
unsigned long magic;
char *name;
} ringbuffer_t;
#ifdef DUMP_FILE
static void dumpbuffer(FILE *fp, char *buf, int count) {
int i = 0;
fprintf(fp, "add: %p %d \n", buf, count);
for (i = 0; i < count; i++) {
fprintf(fp, "%02x ", buf[i]);
if (i % 16 == 15) fprintf(fp, "\n");
}
fprintf(fp, "\n");
fflush(fp);
}
#endif
/************************************************
* CONSTANTS
************************************************/
// Magic number contained in the buffer handles to check if
// they are valid (debug)
#define MAGIC_NUMBER 0xA234C678UL
// TODO: better implementation
#define SLEEP_TIME 1000
/************************************************
* PUBLIC API
************************************************/
int ringbuffer_read(rbuf_handle_t handle, char *dst, int count, rbuf_mode_t mode) {
(void)mode;
ringbuffer_t *rbuf = (ringbuffer_t *)handle;
assert(rbuf);
assert(rbuf->magic == MAGIC_NUMBER);
assert(rbuf->buffer);
assert(rbuf);
assert(count < rbuf->buffer_size);
if (count <= 0) return 0;
// Cannot read more than what is available
count = (count < rbuf->read_avail) ? count : rbuf->read_avail;
int over = rbuf->read_pos + count - rbuf->buffer_size;
if (over > 0) {
memcpy(dst, rbuf->buffer + rbuf->read_pos, count - over);
// Roll back from the beginning of the buffer
memcpy(dst + count - over, rbuf->buffer, over);
rbuf->read_pos = over;
} else {
memcpy(dst, rbuf->buffer + rbuf->read_pos, count);
rbuf->read_pos += count;
}
#ifdef DUMP_FILE
dumpbuffer(rbuf->r_fp, dst, count);
#endif
rbuf->write_avail += count;
rbuf->read_avail -= count;
return count;
}
int ringbuffer_peek(rbuf_handle_t handle, char *dst, int count, rbuf_mode_t mode) {
(void)mode;
ringbuffer_t *rbuf = (ringbuffer_t *)handle;
assert(rbuf);
assert(rbuf->magic == MAGIC_NUMBER);
assert(rbuf->buffer);
assert(rbuf);
assert(count < rbuf->buffer_size);
if (count <= 0) return 0;
// Cannot read more than what is available
count = (count < rbuf->read_avail) ? count : rbuf->read_avail;
int over = rbuf->read_pos + count - rbuf->buffer_size;
if (over > 0) {
memcpy(dst, rbuf->buffer + rbuf->read_pos, count - over);
// Roll back from the beginning of the buffer
memcpy(dst + count - over, rbuf->buffer, over);
} else {
memcpy(dst, rbuf->buffer + rbuf->read_pos, count);
}
#ifdef DUMP_FILE
dumpbuffer(rbuf->r_fp, dst, count);
#endif
return count;
}
int ringbuffer_write(rbuf_handle_t handle, const char *src, int count, rbuf_mode_t mode) {
(void)mode;
ringbuffer_t *rbuf = (ringbuffer_t *)handle;
assert(rbuf);
assert(rbuf->magic == MAGIC_NUMBER);
assert(rbuf->buffer);
assert(src);
if (count <= 0) return 0;
count = (count < rbuf->write_avail) ? count : rbuf->write_avail;
int over = rbuf->write_pos + count - rbuf->buffer_size;
#ifdef DUMP_FILE
dumpbuffer(rbuf->w_fp, src, count);
#endif
if (over > 0) {
memcpy(rbuf->buffer + rbuf->write_pos, src, count - over);
// Roll back from the beginning of the buffer
memcpy(rbuf->buffer, (char *)src + count - over, over);
rbuf->write_pos = over;
} else {
memcpy(rbuf->buffer + rbuf->write_pos, src, count);
rbuf->write_pos += count;
}
rbuf->write_avail -= count;
rbuf->read_avail += count;
return count;
}
int ringbuffer_read_avail(rbuf_handle_t handle) {
ringbuffer_t *rbuf = (ringbuffer_t *)handle;
assert(rbuf);
int val = rbuf->read_avail;
return val;
}
int ringbuffer_write_avail(rbuf_handle_t handle) {
ringbuffer_t *rbuf = (ringbuffer_t *)handle;
assert(rbuf);
int val = rbuf->write_avail;
return val;
}
int ringbuffer_cleanreset(rbuf_handle_t handle) {
ringbuffer_t *rbuf = (ringbuffer_t *)handle;
assert(rbuf);
rbuf->read_pos = 0;
rbuf->write_pos = 0;
rbuf->read_avail = 0;
rbuf->write_avail = rbuf->buffer_size;
return 0;
}
rbuf_handle_t ringbuffer_create(int size, const char *name) {
if (size <= 0) {
return NULL;
}
// Allocate handle
ringbuffer_t *rbuf = (ringbuffer_t *)malloc(sizeof(ringbuffer_t));
if (!rbuf) {
SUBTITLE_LOGE("ERROR: failed to allocate handle: %m");
goto error;
}
// Initialize members
rbuf->magic = MAGIC_NUMBER;
rbuf->buffer_size = size;
rbuf->read_pos = 0;
rbuf->write_pos = 0;
rbuf->read_avail = 0;
rbuf->write_avail = size;
rbuf->name = strdup(name); // strdup malloc inside
#ifdef DUMP_FILE
char filename[256];
sprintf(filename, "/data/ringbuffer_%s_write.dump", name);
rbuf->w_fp = fopen(filename, "w+");
sprintf(filename, "/data/ringbuffer_%s_read.dump", name);
rbuf->r_fp = fopen(filename, "w+");
#endif
// Allocate buffer
rbuf->buffer = (char *)malloc(size);
if (!(rbuf->buffer)) {
SUBTITLE_LOGI("ERROR: failed to allocate buffer\n");
goto error;
}
return rbuf;
error:
if (rbuf) {
if (rbuf->name) {
free(rbuf->name);
rbuf->name = NULL;
}
if (rbuf->buffer) {
free(rbuf->buffer);
rbuf->buffer = NULL;
}
free(rbuf);
rbuf = NULL;
}
return NULL;
}
void ringbuffer_free(rbuf_handle_t handle) {
ringbuffer_t *rbuf = (ringbuffer_t *)handle;
if (!rbuf) return;
assert(rbuf->magic == MAGIC_NUMBER);
#ifdef DUMP_FILE
fclose(rbuf->w_fp);
fclose(rbuf->r_fp);
#endif
if (rbuf->buffer) {
free(rbuf->buffer);
}
free(rbuf->name);
free(rbuf);
}