summaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
authorTuomas Virtanen <katajakasa@gmail.com>2018-04-04 23:09:55 +0300
committerTuomas Virtanen <katajakasa@gmail.com>2018-04-04 23:09:55 +0300
commitdf0ba1e67062fba5d9d6464bb6a40e808760b4dc (patch)
treeffeec6c5fd95ffb4af896b2fd96b2b5f74172fa1 /src/internal
parentf5188876ce863b26f1f5c9c00cb788642ad84afd (diff)
Fix bitmap subtitle playback
Diffstat (limited to 'src/internal')
-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
6 files changed, 88 insertions, 100 deletions
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) {