summaryrefslogtreecommitdiff
path: root/src/internal/subtitle/renderers
diff options
context:
space:
mode:
authorTuomas Virtanen <katajakasa@gmail.com>2018-01-15 20:04:09 +0200
committerTuomas Virtanen <katajakasa@gmail.com>2018-01-15 20:04:09 +0200
commiteace70f1c1c7ba7339713666a76213acf1125202 (patch)
treea13d1468406644b91e3bc50bc139ebc32cda2e90 /src/internal/subtitle/renderers
parent2267d51d2b402c377a21bf03be6fc51b251f063b (diff)
Dump reorganized code
Diffstat (limited to 'src/internal/subtitle/renderers')
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c188
-rw-r--r--src/internal/subtitle/renderers/kitsubimage.c51
-rw-r--r--src/internal/subtitle/renderers/kitsubrenderer.c32
3 files changed, 271 insertions, 0 deletions
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
new file mode 100644
index 0000000..d0c5a80
--- /dev/null
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -0,0 +1,188 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#include <ass/ass.h>
+#include <SDL2/SDL_Surface.h>
+
+#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/kitlibstate.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) {
+ 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 an, ao, x, y, x_off;
+ dst += img->dst_y * surface->pitch;
+
+ for(y = 0; y < img->h; y++) {
+ for(x = 0; x < img->w; x++) {
+ x_off = (img->dst_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];
+ }
+ }
+ }
+ src += img->stride;
+ dst += surface->pitch;
+ }
+}
+
+static int ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *dst) {
+ assert(ren != NULL);
+ assert(src != NULL);
+ assert(dst != NULL);
+
+ Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ AVSubtitle *sub = src;
+ SDL_Surface *surface = dst;
+ unsigned int now = start_pts * 1000;
+ int change = 0;
+
+ // 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.
+ ASS_Image *image = ass_render_frame(ass_ren->renderer, ass_ren->track, now, &change);
+ if(change <= 0) {
+ return -1;
+ }
+
+ for(; image; image = image->next) {
+ if(image->w == 0 || image->h == 0)
+ continue;
+ _ProcessAssImage(surface, image);
+ }
+
+ // We tell subtitle handler to clear output before adding this frame.
+ return 0;
+}
+
+static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
+ if(ren == NULL) return;
+
+ Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ ass_renderer_done(ass_ren->renderer);
+ free(ass_ren);
+}
+
+Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(const Kit_Decoder *dec, int w, int h) {
+ assert(dec != NULL);
+ assert(w >= 0);
+ assert(h >= 0);
+
+ // Make sure that libass library has been initialized + get handle
+ Kit_LibraryState *state = Kit_GetLibraryState();
+ if(state->libass_handle == NULL) {
+ Kit_SetError("Libass library has not been initialized");
+ return NULL;
+ }
+
+ // First allocate the generic decoder component
+ Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer();
+ if(ren == NULL) {
+ goto exit_0;
+ }
+
+ // Next, allocate ASS subtitle renderer context.
+ Kit_ASSSubtitleRenderer *ass_ren = calloc(1, sizeof(Kit_ASSSubtitleRenderer));
+ if(ass_ren == NULL) {
+ goto exit_1;
+ }
+
+ // Initialize libass renderer
+ ASS_Renderer *ass_renderer = ass_renderer_init(state->libass_handle);
+ if(ass_renderer == NULL) {
+ Kit_SetError("Unable to initialize libass renderer");
+ goto exit_2;
+ }
+
+ // Read fonts from attachment streams and give them to libass
+ for(int j = 0; j < dec->format_ctx->nb_streams; j++) {
+ AVStream *st = dec->format_ctx->streams[j];
+ if(st->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT && attachment_is_font(st)) {
+ const AVDictionaryEntry *tag = av_dict_get(
+ st->metadata,
+ "filename",
+ NULL,
+ AV_DICT_MATCH_CASE);
+ if(tag) {
+ ass_add_font(
+ state->libass_handle,
+ tag->value,
+ (char*)st->codec->extradata,
+ st->codec->extradata_size);
+ }
+ }
+ }
+
+ // Init libass fonts and window frame size
+ ass_set_fonts(
+ ass_renderer,
+ NULL, "sans-serif",
+ ASS_FONTPROVIDER_AUTODETECT,
+ NULL, 1);
+ ass_set_frame_size(ass_renderer, w, h);
+ ass_set_hinting(ass_renderer, ASS_HINTING_NONE);
+
+ // Initialize libass track
+ ASS_Track *ass_track = ass_new_track(state->libass_handle);
+ if(ass_track == NULL) {
+ Kit_SetError("Unable to initialize libass track");
+ goto exit_3;
+ }
+
+ // Set up libass track headers (ffmpeg provides these)
+ if(dec->codec_ctx->subtitle_header) {
+ ass_process_codec_private(
+ ass_track,
+ (char*)dec->codec_ctx->subtitle_header,
+ dec->codec_ctx->subtitle_header_size);
+ }
+
+ // 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->userdata = ass_ren;
+ return ren;
+
+exit_3:
+ ass_renderer_done(ass_renderer);
+exit_2:
+ free(ass_ren);
+exit_1:
+ Kit_CloseSubtitleRenderer(ren);
+exit_0:
+ return NULL;
+}
diff --git a/src/internal/subtitle/renderers/kitsubimage.c b/src/internal/subtitle/renderers/kitsubimage.c
new file mode 100644
index 0000000..15a7432
--- /dev/null
+++ b/src/internal/subtitle/renderers/kitsubimage.c
@@ -0,0 +1,51 @@
+#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
+
+int filler() { return 0; }
+
+/*
+void _HandleBitmapSubtitle(Kit_SubtitlePacket** spackets, int *n, Kit_Player *player, double pts, AVSubtitle *sub, AVSubtitleRect *rect) {
+ if(rect->nb_colors == 256) {
+ // Paletted image based subtitles. Convert and set palette.
+ SDL_Surface *s = SDL_CreateRGBSurfaceFrom(
+ rect->data[0],
+ rect->w, rect->h, 8,
+ rect->linesize[0],
+ 0, 0, 0, 0);
+
+ SDL_SetPaletteColors(s->format->palette, (SDL_Color*)rect->data[1], 0, 256);
+
+ Uint32 rmask, gmask, bmask, amask;
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ rmask = 0xff000000;
+ gmask = 0x00ff0000;
+ bmask = 0x0000ff00;
+ amask = 0x000000ff;
+ #else
+ rmask = 0x000000ff;
+ gmask = 0x0000ff00;
+ bmask = 0x00ff0000;
+ amask = 0xff000000;
+ #endif
+ SDL_Surface *tmp = SDL_CreateRGBSurface(
+ 0, rect->w, rect->h, 32,
+ rmask, gmask, bmask, amask);
+ SDL_BlitSurface(s, NULL, tmp, NULL);
+ SDL_FreeSurface(s);
+
+ SDL_Rect *dst_rect = malloc(sizeof(SDL_Rect));
+ dst_rect->x = rect->x;
+ dst_rect->y = rect->y;
+ dst_rect->w = rect->w;
+ dst_rect->h = rect->h;
+
+ double start = pts + (sub->start_display_time / 1000.0f);
+ double end = -1;
+ if(sub->end_display_time < UINT_MAX) {
+ end = pts + (sub->end_display_time / 1000.0f);
+ }
+
+ spackets[(*n)++] = _CreateSubtitlePacket(start, end, dst_rect, tmp);
+ }
+}
+
+*/ \ No newline at end of file
diff --git a/src/internal/subtitle/renderers/kitsubrenderer.c b/src/internal/subtitle/renderers/kitsubrenderer.c
new file mode 100644
index 0000000..f7f95a7
--- /dev/null
+++ b/src/internal/subtitle/renderers/kitsubrenderer.c
@@ -0,0 +1,32 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include "kitchensink/kiterror.h"
+#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
+
+
+Kit_SubtitleRenderer* Kit_CreateSubtitleRenderer() {
+ // 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;
+ }
+ return ren;
+}
+
+int Kit_RunSubtitleRenderer(Kit_SubtitleRenderer *ren, void *src, double start_pts, void *surface) {
+ if(ren == NULL)
+ return 1;
+ if(ren->ren_render != NULL)
+ return ren->ren_render(ren, src, start_pts, surface);
+ return 1;
+}
+
+void Kit_CloseSubtitleRenderer(Kit_SubtitleRenderer *ren) {
+ if(ren == NULL)
+ return;
+ if(ren->ren_close != NULL)
+ ren->ren_close(ren);
+ free(ren);
+}