summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/kitchensink/internal/kitdecoder.h1
-rw-r--r--include/kitchensink/internal/subtitle/kitsubtitlepacket.h18
-rw-r--r--include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h5
-rw-r--r--include/kitchensink/internal/utils/kitbuffer.h2
-rw-r--r--include/kitchensink/internal/utils/kitlog.h2
-rw-r--r--src/internal/kitdecoder.c8
-rw-r--r--src/internal/subtitle/kitsubtitle.c138
-rw-r--r--src/internal/subtitle/kitsubtitlepacket.c19
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c53
-rw-r--r--src/internal/subtitle/renderers/kitsubrenderer.c9
-rw-r--r--src/internal/utils/kitbuffer.c23
11 files changed, 201 insertions, 77 deletions
diff --git a/include/kitchensink/internal/kitdecoder.h b/include/kitchensink/internal/kitdecoder.h
index 5d494e8..6ec209e 100644
--- a/include/kitchensink/internal/kitdecoder.h
+++ b/include/kitchensink/internal/kitdecoder.h
@@ -46,6 +46,7 @@ KIT_LOCAL AVPacket* Kit_ReadDecoderInput(Kit_Decoder *dec);
KIT_LOCAL int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet);
KIT_LOCAL void* Kit_PeekDecoderOutput(Kit_Decoder *dec);
KIT_LOCAL void Kit_AdvanceDecoderOutput(Kit_Decoder *dec);
+KIT_LOCAL void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback foreach_cb, void *userdata);
KIT_LOCAL void Kit_ClearDecoderBuffers(Kit_Decoder *dec);
KIT_LOCAL int Kit_RunDecoder(Kit_Decoder *dec);
KIT_LOCAL void Kit_ClearDecoderInput(Kit_Decoder *dec);
diff --git a/include/kitchensink/internal/subtitle/kitsubtitlepacket.h b/include/kitchensink/internal/subtitle/kitsubtitlepacket.h
new file mode 100644
index 0000000..989cde7
--- /dev/null
+++ b/include/kitchensink/internal/subtitle/kitsubtitlepacket.h
@@ -0,0 +1,18 @@
+#ifndef KITSUBTITLEPACKET_H
+#define KITSUBTITLEPACKET_H
+
+#include <SDL2/SDL_Surface.h>
+
+typedef struct Kit_SubtitlePacket {
+ double pts_start;
+ double pts_end;
+ int x;
+ int y;
+ SDL_Surface *surface;
+} Kit_SubtitlePacket;
+
+Kit_SubtitlePacket* Kit_CreateSubtitlePacket(
+ double pts_start, double pts_end, int pos_x, int pos_y, SDL_Surface *surface);
+void Kit_FreeSubtitlePacket(Kit_SubtitlePacket *packet);
+
+#endif // KITSUBTITLEPACKET_H
diff --git a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
index b24161a..e237546 100644
--- a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
+++ b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
@@ -5,8 +5,9 @@
#include "kitchensink/kitformats.h"
typedef struct Kit_SubtitleRenderer Kit_SubtitleRenderer;
+//typedef struct Kit_SubtitlePacket Kit_SubtitlePacket;
-typedef int (*ren_render_cb)(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *surface);
+typedef Kit_SubtitlePacket* (*ren_render_cb)(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
typedef void (*ren_close_cb)(Kit_SubtitleRenderer *ren);
struct Kit_SubtitleRenderer {
@@ -16,7 +17,7 @@ struct Kit_SubtitleRenderer {
};
KIT_LOCAL Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer();
-KIT_LOCAL int Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *surface);
+KIT_LOCAL Kit_SubtitlePacket* Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
KIT_LOCAL void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren);
#endif // KITSUBRENDERER_H
diff --git a/include/kitchensink/internal/utils/kitbuffer.h b/include/kitchensink/internal/utils/kitbuffer.h
index 4d0f8cc..67d93c3 100644
--- a/include/kitchensink/internal/utils/kitbuffer.h
+++ b/include/kitchensink/internal/utils/kitbuffer.h
@@ -6,6 +6,7 @@
typedef struct Kit_Buffer Kit_Buffer;
typedef void (*Kit_BufferFreeCallback)(void*);
+typedef void (*Kit_ForEachItemCallback)(void*, void *userdata);
struct Kit_Buffer {
unsigned int read_p;
@@ -23,6 +24,7 @@ KIT_LOCAL void* Kit_ReadBuffer(Kit_Buffer *buffer);
KIT_LOCAL void* Kit_PeekBuffer(const Kit_Buffer *buffer);
KIT_LOCAL void Kit_AdvanceBuffer(Kit_Buffer *buffer);
KIT_LOCAL int Kit_WriteBuffer(Kit_Buffer *buffer, void *ptr);
+KIT_LOCAL void Kit_ForEachItemInBuffer(const Kit_Buffer *buffer, Kit_ForEachItemCallback cb, void *userdata);
KIT_LOCAL int Kit_IsBufferFull(const Kit_Buffer *buffer);
#endif // KITBUFFER_H
diff --git a/include/kitchensink/internal/utils/kitlog.h b/include/kitchensink/internal/utils/kitlog.h
index 1a56e53..56ff493 100644
--- a/include/kitchensink/internal/utils/kitlog.h
+++ b/include/kitchensink/internal/utils/kitlog.h
@@ -3,9 +3,11 @@
#ifdef NDEBUG
#define LOG(...)
+ #define LOGFLUSH()
#else
#include <stdio.h>
#define LOG(...) fprintf(stderr, __VA_ARGS__)
+ #define LOGFLUSH() fflush(stderr)
#endif
#endif // KITLOG_H
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index 2d6891b..9c2af91 100644
--- a/src/internal/kitdecoder.c
+++ b/src/internal/kitdecoder.c
@@ -167,6 +167,14 @@ void* Kit_PeekDecoderOutput(Kit_Decoder *dec) {
return ret;
}
+void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback cb, void *userdata) {
+ assert(dec != NULL);
+ if(SDL_LockMutex(dec->lock[KIT_DEC_OUT]) == 0) {
+ Kit_ForEachItemInBuffer(dec->buffer[KIT_DEC_OUT], cb, userdata);
+ SDL_UnlockMutex(dec->lock[KIT_DEC_OUT]);
+ }
+}
+
void Kit_AdvanceDecoderOutput(Kit_Decoder *dec) {
assert(dec != NULL);
if(SDL_LockMutex(dec->lock[KIT_DEC_OUT]) == 0) {
diff --git a/src/internal/subtitle/kitsubtitle.c b/src/internal/subtitle/kitsubtitle.c
index d960044..e11c74a 100644
--- a/src/internal/subtitle/kitsubtitle.c
+++ b/src/internal/subtitle/kitsubtitle.c
@@ -6,7 +6,9 @@
#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/internal/kitlibstate.h"
+#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/kitsubtitle.h"
#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
#include "kitchensink/internal/subtitle/renderers/kitsubass.h"
@@ -14,7 +16,7 @@
#include "kitchensink/internal/utils/kithelpers.h"
-#define KIT_SUBTITLE_OUT_SIZE 32
+#define KIT_SUBTITLE_OUT_SIZE 1024
typedef struct Kit_SubtitleDecoder {
Kit_SubtitleFormat *format;
@@ -23,27 +25,12 @@ typedef struct Kit_SubtitleDecoder {
int w;
int h;
int output_state;
+ SDL_Surface *tmp_buffer;
} Kit_SubtitleDecoder;
-typedef struct Kit_SubtitlePacket {
- double pts_start;
- double pts_end;
- SDL_Surface *surface;
-} Kit_SubtitlePacket;
-
-
-static Kit_SubtitlePacket* _CreateSubtitlePacket(double pts_start, double pts_end, SDL_Surface *surface) {
- Kit_SubtitlePacket *p = calloc(1, sizeof(Kit_SubtitlePacket));
- p->pts_start = pts_start;
- p->pts_end = pts_end;
- p->surface = surface;
- return p;
-}
static void free_out_subtitle_packet_cb(void *packet) {
- Kit_SubtitlePacket *p = packet;
- SDL_FreeSurface(p->surface);
- free(p);
+ Kit_FreeSubtitlePacket((Kit_SubtitlePacket*)packet);
}
static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
@@ -70,25 +57,18 @@ static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
double start = pts + (subtitle_dec->scratch_frame.start_display_time / 1000.0f);
double end = pts + (subtitle_dec->scratch_frame.end_display_time / 1000.0f);
- // Surface to render on
- SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(
- 0, subtitle_dec->w, subtitle_dec->h, 32, SDL_PIXELFORMAT_RGBA32);
- memset(surface->pixels, 0, surface->pitch * surface->h);
-
// Create a packet. This should be filled by renderer.
- Kit_SubtitlePacket *out_packet = _CreateSubtitlePacket(start, end, surface);
- int ret = Kit_RunSubtitleRenderer(
- subtitle_dec->renderer, &subtitle_dec->scratch_frame, start, surface);
- if(ret == -1) {
- // Renderer failed, free packet.
- free_out_subtitle_packet_cb(out_packet);
- } else {
+ Kit_SubtitlePacket *out_packet = Kit_RunSubtitleRenderer(
+ subtitle_dec->renderer, &subtitle_dec->scratch_frame, start, end);
+ if(out_packet != NULL) {
Kit_WriteDecoderOutput(dec, out_packet);
}
// Free subtitle since it has now been handled
avsubtitle_free(&subtitle_dec->scratch_frame);
}
+
+ LOGFLUSH();
}
return 1;
@@ -97,6 +77,7 @@ static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
static void dec_close_subtitle_cb(Kit_Decoder *dec) {
if(dec == NULL) return;
Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ SDL_FreeSurface(subtitle_dec->tmp_buffer);
Kit_CloseSubtitleRenderer(subtitle_dec->renderer);
free(subtitle_dec);
}
@@ -149,16 +130,27 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, Kit_SubtitleFormat
goto exit_2;
}
+ // Allocate temporary screen-sized subtitle buffer
+ SDL_Surface *tmp_buffer = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_RGBA32);
+ if(tmp_buffer == NULL) {
+ goto exit_3;
+ }
+ SDL_FillRect(tmp_buffer, NULL, 0);
+
// Set callbacks and userdata, and we're go
subtitle_dec->format = format;
subtitle_dec->renderer = ren;
subtitle_dec->w = w;
subtitle_dec->h = h;
+ subtitle_dec->tmp_buffer = tmp_buffer;
+ subtitle_dec->output_state = 0;
dec->dec_decode = dec_decode_subtitle_cb;
dec->dec_close = dec_close_subtitle_cb;
dec->userdata = subtitle_dec;
return dec;
+exit_3:
+ Kit_CloseSubtitleRenderer(ren);
exit_2:
free(subtitle_dec);
exit_1:
@@ -167,43 +159,77 @@ exit_0:
return NULL;
}
+
+typedef struct {
+ double sync_ts;
+ SDL_Surface *surface;
+ int rendered;
+} tmp_sub_image;
+
+
+static void _merge_subtitle_texture(void *ptr, void *userdata) {
+ tmp_sub_image *img = userdata;
+ Kit_SubtitlePacket *packet = ptr;
+
+ // Make sure current time is within presentation range
+ if(packet->pts_start >= img->sync_ts)
+ return;
+ if(packet->pts_end <= img->sync_ts)
+ return;
+
+ // Tell the renderer function that we did something here
+ img->rendered = 1;
+
+ // Blit source whole source surface to target surface in requested coords
+ SDL_Rect dst_rect;
+ dst_rect.x = packet->x;
+ dst_rect.y = packet->y;
+ SDL_BlitSurface(packet->surface, NULL, img->surface, &dst_rect);
+}
+
+
int Kit_GetSubtitleDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
assert(dec != NULL);
assert(texture != NULL);
- double sync_ts = _GetSystemTime() - dec->clock_sync;
- char *clear_scr;
-
Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
- Kit_SubtitlePacket *packet = Kit_PeekDecoderOutput(dec);
- if(packet == NULL) {
- goto exit_0;
+
+ double sync_ts = _GetSystemTime() - dec->clock_sync;
+
+ // If we rendered on last frame, clear the buffer
+ if(subtitle_dec->output_state == 1) {
+ SDL_FillRect(subtitle_dec->tmp_buffer, NULL, 0);
}
- if(packet->pts_start > sync_ts) {
- goto exit_0;
+
+ // Blit all subtitle image rectangles to master buffer
+ tmp_sub_image img;
+ img.sync_ts = sync_ts;
+ img.surface = subtitle_dec->tmp_buffer;
+ img.rendered = 0;
+ Kit_ForEachDecoderOutput(dec, _merge_subtitle_texture, (void*)&img);
+
+ // Clear out old packets
+ Kit_SubtitlePacket *packet = NULL;
+ while((packet = Kit_PeekDecoderOutput(dec)) != NULL) {
+ if(packet->pts_end >= sync_ts)
+ break;
+ Kit_AdvanceDecoderOutput(dec);
+ free_out_subtitle_packet_cb(packet);
}
- if(packet->pts_end < sync_ts) {
- goto exit_1;
+
+ // If nothing was rendered now or last frame, just return. No need to update texture.
+ dec->clock_pos = sync_ts;
+ if(img.rendered == 0 && subtitle_dec->output_state == 0) {
+ return 1;
}
+ subtitle_dec->output_state = img.rendered;
- // Update the texture with our subtitle frame
+ // Update output texture with current buffered image
SDL_UpdateTexture(
texture, NULL,
- packet->surface->pixels,
- packet->surface->pitch);
-
- dec->clock_pos = sync_ts;
- return 0;
-
- // All done.
-exit_1:
- Kit_AdvanceDecoderOutput(dec);
- free_out_subtitle_packet_cb(packet);
-exit_0:
- // Clear subtitle frame
- clear_scr = calloc(1, subtitle_dec->h * subtitle_dec->w * 4);
- SDL_UpdateTexture(texture, NULL, clear_scr, subtitle_dec->w * 4);
- free(clear_scr);
+ subtitle_dec->tmp_buffer->pixels,
+ subtitle_dec->tmp_buffer->pitch);
+ // all done!
return 0;
}
diff --git a/src/internal/subtitle/kitsubtitlepacket.c b/src/internal/subtitle/kitsubtitlepacket.c
new file mode 100644
index 0000000..ff52d39
--- /dev/null
+++ b/src/internal/subtitle/kitsubtitlepacket.c
@@ -0,0 +1,19 @@
+#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
+
+
+Kit_SubtitlePacket* Kit_CreateSubtitlePacket(
+ double pts_start, double pts_end, int pos_x, int pos_y, SDL_Surface *surface)
+{
+ Kit_SubtitlePacket *p = calloc(1, sizeof(Kit_SubtitlePacket));
+ p->pts_start = pts_start;
+ p->pts_end = pts_end;
+ p->x = pos_x;
+ p->y = pos_y;
+ p->surface = surface;
+ return p;
+}
+
+void Kit_FreeSubtitlePacket(Kit_SubtitlePacket *p) {
+ SDL_FreeSurface(p->surface);
+ free(p);
+}
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
index d0c5a80..03b91a1 100644
--- a/src/internal/subtitle/renderers/kitsubass.c
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -5,7 +5,9 @@
#include <SDL2/SDL_Surface.h>
#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/internal/kitlibstate.h"
+#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/utils/kithelpers.h"
#include "kitchensink/internal/subtitle/renderers/kitsubass.h"
@@ -19,19 +21,21 @@ typedef struct Kit_ASSSubtitleRenderer {
ASS_Track *track;
} Kit_ASSSubtitleRenderer;
-static void _ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
+static void _ProcessAssImage(SDL_Surface *surface, const ASS_Image *img, int min_x, int min_y) {
unsigned char r = ((img->color) >> 24) & 0xFF;
unsigned char g = ((img->color) >> 16) & 0xFF;
unsigned char b = ((img->color) >> 8) & 0xFF;
unsigned char a = (img->color) & 0xFF;
unsigned char *src = img->bitmap;
unsigned char *dst = surface->pixels;
+ unsigned int pos_x = img->dst_x - min_x;
+ unsigned int pos_y = img->dst_y - min_y;
unsigned int an, ao, x, y, x_off;
- dst += img->dst_y * surface->pitch;
+ dst += pos_y * surface->pitch;
for(y = 0; y < img->h; y++) {
for(x = 0; x < img->w; x++) {
- x_off = (img->dst_x + x) * 4;
+ x_off = (pos_x + x) * 4;
an = ((255 - a) * src[x]) >> 8; // New alpha
ao = dst[x_off + 3]; // Original alpha
if(ao == 0) {
@@ -53,16 +57,20 @@ static void _ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
}
}
-static int ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *dst) {
+static Kit_SubtitlePacket* ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts) {
assert(ren != NULL);
assert(src != NULL);
- assert(dst != NULL);
Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
AVSubtitle *sub = src;
- SDL_Surface *surface = dst;
+ SDL_Surface *surface = NULL;
+ ASS_Image *image = NULL;
+ ASS_Image *wt_image = NULL;
unsigned int now = start_pts * 1000;
int change = 0;
+ int x0 = INT_MAX, y0 = INT_MAX;
+ int x1 = 0, y1 = 0;
+ int w, h;
// Read incoming subtitle packets to libASS
for(int r = 0; r < sub->num_rects; r++) {
@@ -72,19 +80,40 @@ static int ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double start_
}
// Ask libass to render frames. If there are no changes since last render, stop here.
- ASS_Image *image = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
- if(change <= 0) {
- return -1;
+ wt_image = image = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
+ if(change == 0) {
+ return NULL;
+ }
+ LOG("Change at %f %f\n", start_pts, end_pts);
+
+ // Find dimensions
+ for(image = wt_image; image; image = image->next) {
+ if(image->dst_x < x0)
+ x0 = image->dst_x;
+ if(image->dst_y < y0)
+ y0 = image->dst_y;
+ if(image->dst_x + image->w > x1)
+ x1 = image->dst_x + image->w;
+ if(image->dst_y + image->h > y1)
+ y1 = image->dst_y + image->h;
}
+ w = x1 - x0;
+ h = y1 - y0;
+
+ // Surface to render on
+ surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_RGBA32);
+ SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
+ SDL_FillRect(surface, NULL, 0);
- for(; image; image = image->next) {
+ // Render subimages to the target surface.
+ for(image = wt_image; image; image = image->next) {
if(image->w == 0 || image->h == 0)
continue;
- _ProcessAssImage(surface, image);
+ _ProcessAssImage(surface, image, x0, y0);
}
// We tell subtitle handler to clear output before adding this frame.
- return 0;
+ return Kit_CreateSubtitlePacket(start_pts, end_pts, x0, y0, surface);
}
static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
diff --git a/src/internal/subtitle/renderers/kitsubrenderer.c b/src/internal/subtitle/renderers/kitsubrenderer.c
index f7f95a7..ce3e408 100644
--- a/src/internal/subtitle/renderers/kitsubrenderer.c
+++ b/src/internal/subtitle/renderers/kitsubrenderer.c
@@ -2,6 +2,7 @@
#include <assert.h>
#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
@@ -15,12 +16,12 @@ Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer() {
return ren;
}
-int Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *surface) {
+Kit_SubtitlePacket* Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts) {
if(ren == NULL)
- return 1;
+ return NULL;
if(ren->ren_render != NULL)
- return ren->ren_render(ren, src, start_pts, surface);
- return 1;
+ return ren->ren_render(ren, src, start_pts, end_pts);
+ return NULL;
}
void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren) {
diff --git a/src/internal/utils/kitbuffer.c b/src/internal/utils/kitbuffer.c
index f43d9ba..0133154 100644
--- a/src/internal/utils/kitbuffer.c
+++ b/src/internal/utils/kitbuffer.c
@@ -27,6 +27,8 @@ void Kit_DestroyBuffer(Kit_Buffer *buffer) {
void Kit_ClearBuffer(Kit_Buffer *buffer) {
void *data;
+ if(buffer->free_cb == NULL)
+ return;
while((data = Kit_ReadBuffer(buffer)) != NULL) {
buffer->free_cb(data);
}
@@ -47,12 +49,15 @@ void* Kit_ReadBuffer(Kit_Buffer *buffer) {
return NULL;
}
-KIT_LOCAL void* Kit_PeekBuffer(const Kit_Buffer *buffer) {
+void* Kit_PeekBuffer(const Kit_Buffer *buffer) {
assert(buffer != NULL);
- return buffer->data[buffer->read_p % buffer->size];
+ if(buffer->read_p < buffer->write_p) {
+ return buffer->data[buffer->read_p % buffer->size];
+ }
+ return NULL;
}
-KIT_LOCAL void Kit_AdvanceBuffer(Kit_Buffer *buffer) {
+void Kit_AdvanceBuffer(Kit_Buffer *buffer) {
assert(buffer != NULL);
if(buffer->read_p < buffer->write_p) {
buffer->data[buffer->read_p % buffer->size] = NULL;
@@ -64,6 +69,18 @@ KIT_LOCAL void Kit_AdvanceBuffer(Kit_Buffer *buffer) {
}
}
+void Kit_ForEachItemInBuffer(const Kit_Buffer *buffer, Kit_ForEachItemCallback cb, void *userdata) {
+ unsigned int read_p = buffer->read_p;
+ unsigned int write_p = buffer->write_p;
+ while(read_p < write_p) {
+ cb(buffer->data[read_p++ % buffer->size], userdata);
+ if(read_p >= buffer->size) {
+ read_p = read_p % buffer->size;
+ write_p = write_p % buffer->size;
+ }
+ }
+}
+
int Kit_WriteBuffer(Kit_Buffer *buffer, void *ptr) {
assert(buffer != NULL);
assert(ptr != NULL);