summaryrefslogtreecommitdiff
path: root/src/internal/subtitle/renderers
diff options
context:
space:
mode:
authorTuomas Virtanen <katajakasa@gmail.com>2018-03-31 16:48:17 +0300
committerTuomas Virtanen <katajakasa@gmail.com>2018-03-31 16:48:17 +0300
commit77f1a8d1eb514b65c7f816933b4d11b4a0ce574b (patch)
treeaf1b053957c5a1571675efeeee7108dc1091610c /src/internal/subtitle/renderers
parent591f359765045e68dc3e69742a63377b2b05525f (diff)
Add texture atlas for subtitles
Diffstat (limited to 'src/internal/subtitle/renderers')
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c132
-rw-r--r--src/internal/subtitle/renderers/kitsubimage.c38
-rw-r--r--src/internal/subtitle/renderers/kitsubrenderer.c11
3 files changed, 98 insertions, 83 deletions
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
index 2a9eedf..f59db07 100644
--- a/src/internal/subtitle/renderers/kitsubass.c
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -7,49 +7,30 @@
#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/internal/kitlibstate.h"
#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
+#include "kitchensink/internal/subtitle/kitatlas.h"
#include "kitchensink/internal/utils/kithelpers.h"
#include "kitchensink/internal/subtitle/renderers/kitsubass.h"
-// For compatibility
-#ifndef ASS_FONTPROVIDER_AUTODETECT
-#define ASS_FONTPROVIDER_AUTODETECT 1
-#endif
-
typedef struct Kit_ASSSubtitleRenderer {
ASS_Renderer *renderer;
ASS_Track *track;
} Kit_ASSSubtitleRenderer;
-static void _ProcessAssImage(SDL_Surface *surface, const ASS_Image *img, int min_x, int min_y) {
+static void Kit_ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
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 += pos_y * surface->pitch;
+ unsigned int x, y;
for(y = 0; y < img->h; y++) {
for(x = 0; x < img->w; x++) {
- x_off = (pos_x + x) * 4;
- an = ((255 - a) * src[x]) >> 8; // New alpha
- ao = dst[x_off + 3]; // Original alpha
- if(ao == 0) {
- dst[x_off + 0] = r;
- dst[x_off + 1] = g;
- dst[x_off + 2] = b;
- dst[x_off + 3] = an;
- } else {
- dst[x_off + 3] = 255 - (255 - dst[x_off + 3]) * (255 - an) / 255;
- if(dst[x_off + 3] != 0) {
- dst[x_off + 0] = (dst[x_off + 0] * ao * (255-an) / 255 + r * an ) / dst[x_off + 3];
- dst[x_off + 1] = (dst[x_off + 1] * ao * (255-an) / 255 + g * an ) / dst[x_off + 3];
- dst[x_off + 2] = (dst[x_off + 2] * ao * (255-an) / 255 + b * an ) / dst[x_off + 3];
- }
- }
+ dst[x * 4 + 0] = r;
+ dst[x * 4 + 1] = g;
+ dst[x * 4 + 2] = b;
+ dst[x * 4 + 3] = ((255 - a) * src[x]) >> 8;
}
src += img->stride;
dst += surface->pitch;
@@ -62,67 +43,67 @@ static Kit_SubtitlePacket* ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *sr
Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
AVSubtitle *sub = src;
- 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++) {
- if(sub->rects[r]->ass == NULL)
- continue;
- ass_process_data(ass_ren->track, sub->rects[r]->ass, strlen(sub->rects[r]->ass));
- }
-
- // Ask libass to render frames. If there are no changes since last render, stop here.
- wt_image = image = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
- if(change == 0) {
- return NULL;
- }
-
- // 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);
-
- // 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, x0, y0);
+ if(Kit_LockDecoderOutput(ren->dec) == 0) {
+ for(int r = 0; r < sub->num_rects; r++) {
+ if(sub->rects[r]->ass == NULL)
+ continue;
+ ass_process_data(ass_ren->track, sub->rects[r]->ass, strlen(sub->rects[r]->ass));
+ }
+ Kit_UnlockDecoderOutput(ren->dec);
}
- // We tell subtitle handler to clear output before adding this frame.
- return Kit_CreateSubtitlePacket(start_pts, end_pts, x0, y0, surface);
+ return NULL;
}
static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
if(ren == NULL) return;
Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ ass_free_track(ass_ren->track);
ass_renderer_done(ass_ren->renderer);
free(ass_ren);
}
-Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(const Kit_Decoder *dec, int w, int h) {
+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;
+ 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);
+ Kit_UnlockDecoderOutput(ren->dec);
+ }
+
+ // If there was no change, stop here
+ if(change == 0) {
+ return 0;
+ }
+
+ // 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)
+ continue;
+ surface = SDL_CreateRGBSurfaceWithFormat(0, image->w, image->h, 32, SDL_PIXELFORMAT_RGBA32);
+ SDL_FillRect(surface, NULL, 0);
+ Kit_ProcessAssImage(surface, image);
+ 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);
+ }
+
+ return 0;
+}
+
+Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(Kit_Decoder *dec, int w, int h) {
assert(dec != NULL);
assert(w >= 0);
assert(h >= 0);
@@ -135,7 +116,7 @@ Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(const Kit_Decoder *dec, int
}
// First allocate the generic decoder component
- Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer();
+ Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer(dec);
if(ren == NULL) {
goto exit_0;
}
@@ -196,13 +177,12 @@ Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(const Kit_Decoder *dec, int
dec->codec_ctx->subtitle_header_size);
}
- LOG("kekekekee\n");
-
// Set callbacks and userdata, and we're go
ass_ren->renderer = ass_renderer;
ass_ren->track = ass_track;
ren->ren_render = ren_render_ass_cb;
ren->ren_close = ren_close_ass_cb;
+ ren->ren_get_data = ren_get_data_cb;
ren->userdata = ass_ren;
return ren;
diff --git a/src/internal/subtitle/renderers/kitsubimage.c b/src/internal/subtitle/renderers/kitsubimage.c
index 4cd5b52..e39aae7 100644
--- a/src/internal/subtitle/renderers/kitsubimage.c
+++ b/src/internal/subtitle/renderers/kitsubimage.c
@@ -5,6 +5,7 @@
#include "kitchensink/kiterror.h"
#include "kitchensink/internal/utils/kitlog.h"
+#include "kitchensink/internal/subtitle/kitatlas.h"
#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
@@ -19,6 +20,7 @@ static void _ProcessSubImage(SDL_Surface *surface, const AVSubtitleRect *rect, i
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) {
@@ -28,7 +30,7 @@ static Kit_SubtitlePacket* ren_render_image_cb(Kit_SubtitleRenderer *ren, void *
AVSubtitle *sub = src;
SDL_Surface *surface = NULL;
int x0 = INT_MAX, y0 = INT_MAX;
- int x1 = 0, y1 = 0;
+ int x1 = INT_MIN, y1 = INT_MIN;
int w, h;
int has_content = 0;
@@ -54,7 +56,6 @@ static Kit_SubtitlePacket* ren_render_image_cb(Kit_SubtitleRenderer *ren, void *
w = x1 - x0;
h = y1 - y0;
- LOG("x, y = %d, %d w, h = %d, %d\n", x0, y0, w, h);
// Surface to render on
surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_RGBA32);
@@ -69,24 +70,49 @@ static Kit_SubtitlePacket* ren_render_image_cb(Kit_SubtitleRenderer *ren, void *
_ProcessSubImage(surface, r, x0, y0);
}
- LOG("Setting %f, %f\n", start_pts, end_pts);
- return Kit_CreateSubtitlePacket(start_pts, end_pts, x0, y0, surface);
+ SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
+ return Kit_CreateSubtitlePacket(KIT_SUBTITLE_PACKET_ADD, start_pts, end_pts, x0, y0, surface);
}
+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;
+ while((packet = Kit_PeekDecoderOutput(ren->dec)) != NULL) {
+ if(packet->pts_end < current_pts) {
+ Kit_AdvanceDecoderOutput(ren->dec);
+ Kit_FreeSubtitlePacket(packet);
+ }
+ if(packet->pts_start > current_pts) {
+ break;
+ }
+
+ 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;
+ }
+ return 0;
+}
-Kit_SubtitleRenderer* Kit_CreateImageSubtitleRenderer(const Kit_Decoder *dec, int w, int h) {
+Kit_SubtitleRenderer* Kit_CreateImageSubtitleRenderer(Kit_Decoder *dec, int w, int h) {
assert(dec != NULL);
assert(w >= 0);
assert(h >= 0);
// Allocate a new renderer
- Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer();
+ Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer(dec);
if(ren == NULL) {
return NULL;
}
// Only renderer required, no other data.
ren->ren_render = ren_render_image_cb;
+ ren->ren_get_data = ren_get_data_cb;
ren->ren_close = NULL;
ren->userdata = NULL;
return ren;
diff --git a/src/internal/subtitle/renderers/kitsubrenderer.c b/src/internal/subtitle/renderers/kitsubrenderer.c
index ce3e408..0e628bc 100644
--- a/src/internal/subtitle/renderers/kitsubrenderer.c
+++ b/src/internal/subtitle/renderers/kitsubrenderer.c
@@ -6,13 +6,14 @@
#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
-Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer() {
+Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer(Kit_Decoder *dec) {
// Allocate renderer and make sure allocation was a success
Kit_SubtitleRenderer *ren = calloc(1, sizeof(Kit_SubtitleRenderer));
if(ren == NULL) {
Kit_SetError("Unable to allocate kit subtitle renderer");
return NULL;
}
+ ren->dec = dec;
return ren;
}
@@ -24,6 +25,14 @@ Kit_SubtitlePacket* Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src
return NULL;
}
+int Kit_GetSubtitleRendererData(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
+ if(ren == NULL)
+ return 0;
+ if(ren->ren_get_data != NULL)
+ return ren->ren_get_data(ren, atlas, current_pts);
+ return 0;
+}
+
void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren) {
if(ren == NULL)
return;