summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/example_video.c2
-rw-r--r--include/kitchensink/internal/subtitle/kitsubtitlepacket.h10
-rw-r--r--include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h8
-rw-r--r--include/kitchensink/kitsource.h2
-rw-r--r--src/internal/subtitle/kitatlas.c6
-rw-r--r--src/internal/subtitle/kitsubtitle.c22
-rw-r--r--src/internal/subtitle/kitsubtitlepacket.c7
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c30
-rw-r--r--src/internal/subtitle/renderers/kitsubimage.c116
-rw-r--r--src/internal/subtitle/renderers/kitsubrenderer.c7
10 files changed, 97 insertions, 113 deletions
diff --git a/examples/example_video.c b/examples/example_video.c
index a91b025..2b95b7d 100644
--- a/examples/example_video.c
+++ b/examples/example_video.c
@@ -99,7 +99,7 @@ int main(int argc, char *argv[]) {
// Ask for linear texture scaling (better quality)
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
- // Initialize Kitchensink with network support and all formats.
+ // Initialize Kitchensink with network and libass support.
err = Kit_Init(KIT_INIT_NETWORK|KIT_INIT_ASS);
if(err != 0) {
fprintf(stderr, "Unable to initialize Kitchensink: %s", Kit_GetError());
diff --git a/include/kitchensink/internal/subtitle/kitsubtitlepacket.h b/include/kitchensink/internal/subtitle/kitsubtitlepacket.h
index 549c689..0c97e00 100644
--- a/include/kitchensink/internal/subtitle/kitsubtitlepacket.h
+++ b/include/kitchensink/internal/subtitle/kitsubtitlepacket.h
@@ -1,26 +1,22 @@
#ifndef KITSUBTITLEPACKET_H
#define KITSUBTITLEPACKET_H
+#include <stdbool.h>
#include <SDL2/SDL_surface.h>
#include "kitchensink/kitconfig.h"
-typedef enum {
- KIT_SUBTITLE_PACKET_ADD,
- KIT_SUBTITLE_PACKET_CLEAR
-} Kit_SubtitlePacketType;
-
typedef struct Kit_SubtitlePacket {
- Kit_SubtitlePacketType type;
double pts_start;
double pts_end;
int x;
int y;
+ bool clear;
SDL_Surface *surface;
} Kit_SubtitlePacket;
KIT_LOCAL Kit_SubtitlePacket* Kit_CreateSubtitlePacket(
- Kit_SubtitlePacketType type, double pts_start, double pts_end, int pos_x, int pos_y, SDL_Surface *surface);
+ bool clear, double pts_start, double pts_end, int pos_x, int pos_y, SDL_Surface *surface);
KIT_LOCAL 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 af63e1e..5c1a5b6 100644
--- a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
+++ b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
@@ -8,20 +8,20 @@ typedef struct Kit_SubtitleRenderer Kit_SubtitleRenderer;
typedef struct Kit_TextureAtlas Kit_TextureAtlas;
typedef struct Kit_Decoder Kit_Decoder;
-typedef Kit_SubtitlePacket* (*ren_render_cb)(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
+typedef void (*ren_render_cb)(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
typedef int (*ren_get_data_db)(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts);
typedef void (*ren_close_cb)(Kit_SubtitleRenderer *ren);
struct Kit_SubtitleRenderer {
Kit_Decoder *dec;
void *userdata;
- ren_render_cb ren_render; ///< Subtitle rendering function callback
+ ren_render_cb ren_render; ///< Subtitle rendering function callback
ren_get_data_db ren_get_data; ///< Subtitle data getter function callback
- ren_close_cb ren_close; ///< Subtitle renderer close function callback
+ ren_close_cb ren_close; ///< Subtitle renderer close function callback
};
KIT_LOCAL Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer(Kit_Decoder *dec);
-KIT_LOCAL Kit_SubtitlePacket* Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
+KIT_LOCAL void Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts);
KIT_LOCAL int Kit_GetSubtitleRendererData(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts);
KIT_LOCAL void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren);
diff --git a/include/kitchensink/kitsource.h b/include/kitchensink/kitsource.h
index ea85d57..9c4d1b7 100644
--- a/include/kitchensink/kitsource.h
+++ b/include/kitchensink/kitsource.h
@@ -26,7 +26,7 @@ typedef struct Kit_Source {
void *format_ctx; ///< FFmpeg: Videostream format context
} Kit_Source;
-typedef struct Kit_Stream {
+typedef struct Kit_StreamInfo {
int index; ///< Stream index
Kit_StreamType type; ///< Stream type
} Kit_StreamInfo;
diff --git a/src/internal/subtitle/kitatlas.c b/src/internal/subtitle/kitatlas.c
index 4f98a6f..09993b2 100644
--- a/src/internal/subtitle/kitatlas.c
+++ b/src/internal/subtitle/kitatlas.c
@@ -206,16 +206,18 @@ int Kit_AddAtlasItem(Kit_TextureAtlas *atlas, SDL_Surface *surface, SDL_Rect *ta
assert(surface != NULL);
assert(target != NULL);
+ Kit_TextureAtlasItem *item;
+
if(atlas->cur_items >= atlas->max_items) {
- SDL_FreeSurface(surface);
return -1; // Cannot fit, buffer full!
}
- Kit_TextureAtlasItem *item = &atlas->items[atlas->cur_items];
+ item = &atlas->items[atlas->cur_items];
item->cur_shelf = -1;
item->cur_slot = -1;
item->is_copied = false;
item->surface = surface;
+ item->surface->refcount++; // We dont want to needlessly copy; instead increase refcount.
memset(&item->source, 0, sizeof(SDL_Rect));
memcpy(&item->target, target, sizeof(SDL_Rect));
return atlas->cur_items++;
diff --git a/src/internal/subtitle/kitsubtitle.c b/src/internal/subtitle/kitsubtitle.c
index 3185bcd..a1909ee 100644
--- a/src/internal/subtitle/kitsubtitle.c
+++ b/src/internal/subtitle/kitsubtitle.c
@@ -39,6 +39,7 @@ static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(in_packet != NULL);
Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ double pts, start, end;
int frame_finished;
int len;
@@ -50,26 +51,23 @@ static int dec_decode_subtitle_cb(Kit_Decoder *dec, AVPacket *in_packet) {
if(frame_finished) {
// Start and end presentation timestamps for subtitle frame
- double pts = 0;
+ pts = 0;
if(in_packet->pts != AV_NOPTS_VALUE) {
pts = in_packet->pts;
pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
}
- double start = pts + (subtitle_dec->scratch_frame.start_display_time / 1000.0f);
- double end = -1;
- if(subtitle_dec->scratch_frame.end_display_time < UINT_MAX) {
- end = pts + (subtitle_dec->scratch_frame.end_display_time / 1000.0f);
+
+ // If subtitle has no ending time, we set some safety value.
+ if(subtitle_dec->scratch_frame.end_display_time == UINT_MAX) {
+ subtitle_dec->scratch_frame.end_display_time = 30000;
}
+ start = pts + subtitle_dec->scratch_frame.start_display_time / 1000.0f;
+ end = pts + subtitle_dec->scratch_frame.end_display_time / 1000.0f;
+
// Create a packet. This should be filled by renderer.
- Kit_SubtitlePacket *out_packet = Kit_RunSubtitleRenderer(
+ Kit_RunSubtitleRenderer(
subtitle_dec->renderer, &subtitle_dec->scratch_frame, start, end);
- if(end < 0) {
- Kit_ClearDecoderOutput(dec);
- }
- if(out_packet != NULL) {
- Kit_WriteDecoderOutput(dec, out_packet);
- }
// Free subtitle since it has now been handled
avsubtitle_free(&subtitle_dec->scratch_frame);
diff --git a/src/internal/subtitle/kitsubtitlepacket.c b/src/internal/subtitle/kitsubtitlepacket.c
index 78ab90e..f44eee6 100644
--- a/src/internal/subtitle/kitsubtitlepacket.c
+++ b/src/internal/subtitle/kitsubtitlepacket.c
@@ -2,15 +2,18 @@
Kit_SubtitlePacket* Kit_CreateSubtitlePacket(
- Kit_SubtitlePacketType type, double pts_start, double pts_end, int pos_x, int pos_y, SDL_Surface *surface)
+ bool clear, double pts_start, double pts_end, int pos_x, int pos_y, SDL_Surface *surface)
{
Kit_SubtitlePacket *p = calloc(1, sizeof(Kit_SubtitlePacket));
- p->type = type;
p->pts_start = pts_start;
p->pts_end = pts_end;
p->x = pos_x;
p->y = pos_y;
p->surface = surface;
+ if(p->surface != NULL) {
+ p->surface->refcount++; // We dont want to needlessly copy; instead increase refcount.
+ }
+ p->clear = clear;
return p;
}
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
index f59db07..8618a3d 100644
--- a/src/internal/subtitle/renderers/kitsubass.c
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -37,7 +37,7 @@ static void Kit_ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
}
}
-static Kit_SubtitlePacket* ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts) {
+static void ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts) {
assert(ren != NULL);
assert(src != NULL);
@@ -53,8 +53,6 @@ static Kit_SubtitlePacket* ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *sr
}
Kit_UnlockDecoderOutput(ren->dec);
}
-
- return NULL;
}
static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
@@ -68,14 +66,14 @@ static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
static int ren_get_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
- SDL_Surface *surface;
- ASS_Image *image = NULL;
+ SDL_Surface *dst = NULL;
+ ASS_Image *src = NULL;
int change = 0;
unsigned int now = current_pts * 1000;
// First, we tell ASS to render images for us
if(Kit_LockDecoderOutput(ren->dec) == 0) {
- image = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
+ src = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
Kit_UnlockDecoderOutput(ren->dec);
}
@@ -86,18 +84,18 @@ static int ren_get_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, d
// There was some change, process images and add them to atlas
Kit_ClearAtlasContent(atlas);
- for(; image; image = image->next) {
- if(image->w == 0 || image->h == 0)
+ for(; src; src = src->next) {
+ if(src->w == 0 || src->h == 0)
continue;
- surface = SDL_CreateRGBSurfaceWithFormat(0, image->w, image->h, 32, SDL_PIXELFORMAT_RGBA32);
- SDL_FillRect(surface, NULL, 0);
- Kit_ProcessAssImage(surface, image);
+ dst = SDL_CreateRGBSurfaceWithFormat(0, src->w, src->h, 32, SDL_PIXELFORMAT_RGBA32);
+ Kit_ProcessAssImage(dst, src);
SDL_Rect target;
- target.x = image->dst_x;
- target.y = image->dst_y;
- target.w = image->w;
- target.h = image->h;
- Kit_AddAtlasItem(atlas, surface, &target);
+ target.x = src->dst_x;
+ target.y = src->dst_y;
+ target.w = src->w;
+ target.h = src->h;
+ Kit_AddAtlasItem(atlas, dst, &target);
+ SDL_FreeSurface(dst);
}
return 0;
diff --git a/src/internal/subtitle/renderers/kitsubimage.c b/src/internal/subtitle/renderers/kitsubimage.c
index e39aae7..40279a1 100644
--- a/src/internal/subtitle/renderers/kitsubimage.c
+++ b/src/internal/subtitle/renderers/kitsubimage.c
@@ -9,93 +9,81 @@
#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
+typedef struct Kit_SubtitleCBData {
+ Kit_TextureAtlas *atlas;
+ double current_pts;
+} Kit_SubtitleCBData;
-static void _ProcessSubImage(SDL_Surface *surface, const AVSubtitleRect *rect, int min_x, int min_y) {
- SDL_Surface *src = SDL_CreateRGBSurfaceWithFormatFrom(
- rect->data[0], rect->w, rect->h, 8, rect->linesize[0], SDL_PIXELFORMAT_INDEX8);
- SDL_SetPaletteColors(src->format->palette, (SDL_Color*)rect->data[1], 0, 256);
-
- SDL_Rect dst_rect;
- dst_rect.x = rect->x - min_x;
- dst_rect.y = rect->y - min_y;
-
- SDL_BlitSurface(src, NULL, surface, &dst_rect);
- SDL_FreeSurface(src);
-}
-
-static Kit_SubtitlePacket* ren_render_image_cb(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts) {
+static void ren_render_image_cb(Kit_SubtitleRenderer *ren, void *sub_src, double start_pts, double end_pts) {
assert(ren != NULL);
- assert(src != NULL);
+ assert(sub_src != NULL);
- AVSubtitle *sub = src;
- SDL_Surface *surface = NULL;
- int x0 = INT_MAX, y0 = INT_MAX;
- int x1 = INT_MIN, y1 = INT_MIN;
- int w, h;
- int has_content = 0;
+ AVSubtitle *sub = sub_src;
+ SDL_Surface *dst = NULL, *src = NULL;
- // Find sizes of incoming subtitle bitmaps
- for(int n = 0; n < sub->num_rects; n++) {
- AVSubtitleRect *r = sub->rects[n];
- if(r->type != SUBTITLE_BITMAP)
- continue;
- has_content = 1;
- if(r->x < x0)
- x0 = r->x;
- if(r->y < y0)
- y0 = r->y;
- if(r->x + r->w > x1)
- x1 = r->x + r->w;
- if(r->y + r->h > y1)
- y1 = r->y + r->h;
- }
-
- if(has_content == 0) {
- return NULL;
+ // If this subtitle has no rects, we still need to clear screen from old subs
+ if(sub->num_rects == 0) {
+ Kit_WriteDecoderOutput(
+ ren->dec, Kit_CreateSubtitlePacket(true, start_pts, end_pts, 0, 0, NULL));
+ return;
}
- 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);
-
- // Render subimages to the target surface.
+ // Convert subtitle images from paletted to RGBA8888
for(int n = 0; n < sub->num_rects; n++) {
AVSubtitleRect *r = sub->rects[n];
if(r->type != SUBTITLE_BITMAP)
continue;
- _ProcessSubImage(surface, r, x0, y0);
- }
- SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
- return Kit_CreateSubtitlePacket(KIT_SUBTITLE_PACKET_ADD, start_pts, end_pts, x0, y0, surface);
+ src = SDL_CreateRGBSurfaceWithFormatFrom(
+ r->data[0], r->w, r->h, 8, r->linesize[0], SDL_PIXELFORMAT_INDEX8);
+ SDL_SetPaletteColors(src->format->palette, (SDL_Color*)r->data[1], 0, 256);
+ dst = SDL_CreateRGBSurfaceWithFormat(
+ 0, r->w, r->h, 32, SDL_PIXELFORMAT_RGBA32);
+
+ // Blit source to target and free source surface.
+ SDL_BlitSurface(src, NULL, dst, NULL);
+
+ // Create a new packet and write it to output buffer
+ SDL_SetSurfaceBlendMode(dst, SDL_BLENDMODE_BLEND);
+ Kit_WriteDecoderOutput(
+ ren->dec, Kit_CreateSubtitlePacket(false, start_pts, end_pts, r->x, r->y, dst));
+
+ // Free surfaces
+ SDL_FreeSurface(src);
+ SDL_FreeSurface(dst);
+ }
}
static int ren_get_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
// Read any new packets to atlas
Kit_SubtitlePacket *packet = NULL;
+
+ // Clean dead packets
while((packet = Kit_PeekDecoderOutput(ren->dec)) != NULL) {
if(packet->pts_end < current_pts) {
Kit_AdvanceDecoderOutput(ren->dec);
Kit_FreeSubtitlePacket(packet);
+ continue;
}
- if(packet->pts_start > current_pts) {
- break;
+ if(packet->pts_start < current_pts) {
+ if(packet->clear) {
+ Kit_ClearAtlasContent(atlas);
+ }
+ if(packet->surface != NULL) {
+ SDL_Rect target;
+ target.x = packet->x;
+ target.y = packet->y;
+ target.w = packet->surface->w;
+ target.h = packet->surface->h;
+ Kit_AddAtlasItem(atlas, packet->surface, &target);
+ }
+ Kit_AdvanceDecoderOutput(ren->dec);
+ Kit_FreeSubtitlePacket(packet);
+ continue;
}
-
- SDL_Rect target;
- target.x = packet->x;
- target.y = packet->y;
- target.w = packet->surface->w;
- target.h = packet->surface->h;
- // NOTE! Surfaces ARE NOT COPIED! WE DIRECTLY HAND OVER THE POINTER TO EXISTING DATA! This is why we cannot
- // free the surface after adding it to atlas.
- Kit_AddAtlasItem(atlas, packet->surface, &target);
- packet->surface = NULL;
+ break;
}
+
return 0;
}
diff --git a/src/internal/subtitle/renderers/kitsubrenderer.c b/src/internal/subtitle/renderers/kitsubrenderer.c
index 0e628bc..e63cad1 100644
--- a/src/internal/subtitle/renderers/kitsubrenderer.c
+++ b/src/internal/subtitle/renderers/kitsubrenderer.c
@@ -17,12 +17,11 @@ Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer(Kit_Decoder *dec) {
return ren;
}
-Kit_SubtitlePacket* Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts) {
+void Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, double end_pts) {
if(ren == NULL)
- return NULL;
+ return;
if(ren->ren_render != NULL)
- return ren->ren_render(ren, src, start_pts, end_pts);
- return NULL;
+ ren->ren_render(ren, src, start_pts, end_pts);
}
int Kit_GetSubtitleRendererData(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {