Aegisub/contrib/csri/backends/libass/libass_csri.c

259 lines
6.4 KiB
C

/*****************************************************************************
* csri: common subtitle renderer interface
*****************************************************************************
* Copyright (C) 2007 David Lamparter
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
****************************************************************************/
/** libass csri wrapper.
* Indirectly based on code from aegisub,
* (c) 2006-2007, Rodrigo Braz Monteiro, Evgeniy Stepanov
*/
#ifdef HAVE_CONFIG_H
#include "acconf.h"
#endif
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ass/ass.h>
#ifdef _WIN32
# define CSRIAPI __declspec(dllexport)
#else
# ifdef HAVE_GCC_VISIBILITY
# define CSRIAPI __attribute__((visibility ("default")))
# else
# define CSRIAPI
# endif
#endif
#define CSRI_OWN_HANDLES
typedef struct csri_libass_rend {
ass_library_t* ass_library;
} csri_rend;
typedef struct csri_asa_inst {
ass_renderer_t* ass_renderer;
ass_track_t* ass_track;
} csri_inst;
#include <csri/csri.h>
#include <csri/stream.h>
#include <subhelp.h>
static struct csri_libass_rend csri_libass = { NULL };
csri_inst *csri_open_file(csri_rend *renderer,
const char *filename, struct csri_openflag *flags)
{
return subhelp_open_file(renderer, csri_open_mem, filename, flags);
}
csri_inst *csri_open_mem(csri_rend *renderer,
const void *data, size_t length, struct csri_openflag *flags)
{
csri_inst *rv;
if (renderer != &csri_libass)
return NULL;
rv = (csri_inst *)malloc(sizeof(csri_inst));
if (!rv)
return NULL;
rv->ass_renderer = ass_renderer_init(renderer->ass_library);
if (!rv->ass_renderer) {
free(rv);
return NULL;
}
ass_set_font_scale(rv->ass_renderer, 1.);
ass_set_fonts(rv->ass_renderer, NULL, "Sans");
rv->ass_track = ass_read_memory(csri_libass.ass_library,
(void *)data, length, "UTF-8");
if (!rv->ass_track) {
ass_renderer_done(rv->ass_renderer);
free(rv);
return NULL;
}
return rv;
}
void csri_close(csri_inst *inst)
{
ass_free_track(inst->ass_track);
ass_renderer_done(inst->ass_renderer);
free(inst);
}
int csri_request_fmt(csri_inst *inst, const struct csri_fmt *fmt)
{
if (!csri_is_rgb(fmt->pixfmt) || csri_has_alpha(fmt->pixfmt))
return -1;
ass_set_frame_size(inst->ass_renderer, fmt->width, fmt->height);
return 0;
}
void csri_render(csri_inst *inst, struct csri_frame *frame, double time)
{
ass_image_t *img = ass_render_frame(inst->ass_renderer,
inst->ass_track, (int)(time * 1000), NULL);
while (img) {
unsigned bpp, alpha = 256 - (img->color && 0xFF);
int src_d, dst_d;
unsigned char *src, *dst, *endy, *endx;
unsigned char c[3] = {
(img->color >> 8) & 0xFF, /* B */
(img->color >> 16) & 0xFF, /* G */
img->color >> 24 /* R */
};
if ((frame->pixfmt | 1) == CSRI_F__RGB
|| frame->pixfmt == CSRI_F_RGB) {
unsigned char tmp = c[2];
c[2] = c[0];
c[0] = tmp;
}
bpp = frame->pixfmt >= 0x200 ? 3 : 4;
dst = frame->planes[0]
+ img->dst_y * frame->strides[0]
+ img->dst_x * bpp;
if (frame->pixfmt & 1)
dst++;
src = img->bitmap;
src_d = img->stride - img->w;
dst_d = frame->strides[0] - img->w * bpp;
endy = src + img->h * img->stride;
while (src != endy) {
endx = src + img->w;
while (src != endx) {
/* src[x]: 0..255, alpha: 1..256 (see above)
* -> src[x]*alpha: 0<<8..255<<8
* -> need 1..256 for mult => +1
*/
unsigned s = ((*src++ * alpha) >> 8) + 1;
unsigned d = 257 - s;
/* c[0]: 0.255, s/d: 1..256 */
dst[0] = (s*c[0] + d*dst[0]) >> 8;
dst[1] = (s*c[1] + d*dst[1]) >> 8;
dst[2] = (s*c[2] + d*dst[2]) >> 8;
dst += bpp;
}
dst += dst_d;
src += src_d;
}
img = img->next;
}
}
static csri_inst *libass_init_stream(csri_rend *renderer,
const void *header, size_t headerlen,
struct csri_openflag *flags)
{
csri_inst *rv;
if (renderer != &csri_libass)
return NULL;
rv = (csri_inst *)malloc(sizeof(csri_inst));
if (!rv)
return NULL;
rv->ass_renderer = ass_renderer_init(renderer->ass_library);
if (!rv->ass_renderer) {
free(rv);
return NULL;
}
ass_set_font_scale(rv->ass_renderer, 1.);
ass_set_fonts(rv->ass_renderer, NULL, "Sans");
rv->ass_track = ass_new_track(csri_libass.ass_library);
if (!rv->ass_track) {
ass_renderer_done(rv->ass_renderer);
free(rv);
return NULL;
}
ass_process_codec_private(rv->ass_track, (void *)header, headerlen);
return rv;
}
static void libass_push_packet(csri_inst *inst,
const void *packet, size_t packetlen,
double pts_start, double pts_end)
{
ass_process_chunk(inst->ass_track, (void *)packet, packetlen,
(int)(pts_start * 1000), (int)((pts_end - pts_start) * 1000));
}
static struct csri_stream_ext streamext = {
libass_init_stream,
libass_push_packet,
NULL
};
void *csri_query_ext(csri_rend *rend, csri_ext_id extname)
{
if (!rend)
return NULL;
if (!strcmp(extname, CSRI_EXT_STREAM_ASS))
return &streamext;
return NULL;
}
static struct csri_info csri_libass_info = {
"libass",
"0.9.x",
"libass (the MPlayer SSA/ASS renderer, 0.9.x API)",
"Evgeniy Stepanov",
"Copyright (c) 2006, 2007 by Evgeniy Stepanov"
};
struct csri_info *csri_renderer_info(csri_rend *rend)
{
return &csri_libass_info;
}
csri_rend *csri_renderer_byname(const char *name,
const char *specific)
{
if (strcmp(name, csri_libass_info.name))
return NULL;
if (specific && strcmp(specific, csri_libass_info.specific))
return NULL;
return &csri_libass;
}
csri_rend *csri_renderer_default()
{
csri_libass.ass_library = ass_library_init();
if (!csri_libass.ass_library)
return NULL;
ass_set_fonts_dir(csri_libass.ass_library, "");
ass_set_extract_fonts(csri_libass.ass_library, 0);
ass_set_style_overrides(csri_libass.ass_library, NULL);
return &csri_libass;
}
csri_rend *csri_renderer_next(csri_rend *prev)
{
return NULL;
}