Add changes from

http://greg.geekmind.org/mplayer/libass-snapshot-20090214.tar.gz

* \be filter with [1,2,1] kernel (like vsfilter)
* "decimal point" support, e.g. numbers with fractional parts are dealt with
  correctly
* shadow without border
* "compromise" fix for transparency + aa
* misc fixes: \be and \blur radius and a memory leak
* proper compositing of overlapping translucent outlines

Originally committed to SVN as r2733.
This commit is contained in:
Amar Takhar 2009-02-14 19:19:35 +00:00
parent 1f47e17d66
commit 2c2f85a93d
5 changed files with 307 additions and 57 deletions

View file

@ -39,10 +39,15 @@ struct ass_synth_priv_s {
unsigned *g; unsigned *g;
unsigned *gt2; unsigned *gt2;
double radius; double radius;
}; };
struct ass_be_priv_s {
int size;
unsigned char *buf;
};
static const unsigned int maxcolor = 255; static const unsigned int maxcolor = 255;
static const unsigned base = 256; static const unsigned base = 256;
@ -52,11 +57,14 @@ static int generate_tables(ass_synth_priv_t* priv, double radius)
int mx, i; int mx, i;
double volume_diff, volume_factor = 0; double volume_diff, volume_factor = 0;
unsigned volume; unsigned volume;
if (priv->radius == radius) if (priv->radius == radius)
return 0; return 0;
else else {
priv->radius = radius; priv->radius = radius;
if (priv->g) free(priv->g);
if (priv->gt2) free(priv->gt2);
}
priv->g_r = ceil(radius); priv->g_r = ceil(radius);
priv->g_w = 2*priv->g_r+1; priv->g_w = 2*priv->g_r+1;
@ -115,6 +123,7 @@ static void resize_tmp(ass_synth_priv_t* priv, int w, int h)
ass_synth_priv_t* ass_synth_init(double radius) ass_synth_priv_t* ass_synth_init(double radius)
{ {
ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t)); ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t));
priv->g = priv->gt2 = 0;
generate_tables(priv, radius); generate_tables(priv, radius);
return priv; return priv;
} }
@ -130,7 +139,7 @@ void ass_synth_done(ass_synth_priv_t* priv)
free(priv); free(priv);
} }
static bitmap_t* alloc_bitmap(int w, int h) bitmap_t* alloc_bitmap(int w, int h)
{ {
bitmap_t* bm; bitmap_t* bm;
bm = calloc(1, sizeof(bitmap_t)); bm = calloc(1, sizeof(bitmap_t));
@ -242,7 +251,7 @@ static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
unsigned char c_g, c_o; unsigned char c_g, c_o;
c_g = g[x]; c_g = g[x];
c_o = o[x]; c_o = o[x];
o[x] = (c_o > c_g) ? c_o - c_g : 0; o[x] = (c_o > c_g) ? c_o - c_g/2 : 0;
s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF; s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
} }
g += bm_g->w; g += bm_g->w;
@ -254,12 +263,86 @@ static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
return bm_s; return bm_s;
} }
// \be blur with [1,2,1] matrix
static void be_blur(unsigned char *buf, ass_be_priv_t* priv, int w, int h) {
unsigned int x, y;
unsigned int p;
unsigned char *tmp_buf = priv->buf;
const int wh = w*h;
if (priv->size < wh) {
priv->buf = realloc(priv->buf, wh);
priv->size = wh;
tmp_buf = priv->buf;
printf("resized priv to %d bytes\n", wh);
}
memset(tmp_buf, 0, wh);
for (y=0; y<h; y++)
for (x=1; x<w-1; x++) {
p = buf[y*w+x-1];
p += 2 * buf[y*w+x];
p += buf[y*w+x+1];
p = p >> 2;
tmp_buf[y*w+x] = p;
}
for (x=0; x<w; x++)
for (y=1; y<h-1; y++) {
p = tmp_buf[((y-1)*w+x)];
p += 2 * tmp_buf[y*w+x];
p += tmp_buf[((y+1)*w+x)];
p = p >> 2;
buf[y*w+x] = p;
}
//free(tmp_buf);
}
/*
static void get_overlap(bitmap_t* a, bitmap_t* b) {
int left, top, bottom, right;
int old_left, old_top, old_w, old_h;
int cur_left, cur_top, cur_w, cur_h;
// Calculate overlap as coordinates
left = (a->left > b->left) ? a->left : b-> left;
top = (a->top > b->top) ? a->top : b->top;
right = ((a->left+a->w) < (b->left+b->w)) ?
(a->left+a->w) : (b->left+b->w);
bottom = ((a->top+a->h) < (b->top+b->h)) ?
(a->top+a->h) : (b->top+b->h);
// Check whether overlap rect is valid
// Just return if it isn't...
if ((right <= left) || (bottom <= top))
return;
printf("coord overlap %dx%d+%dx%d\n", left, top, right, bottom);
// Translate into coordinates+width/height for each bitmap
old_left = left-(a->left);
old_top = top-(a->top);
old_w = right-left;
old_h = bottom-top;
printf("bitmap overlap %dx%d+%dx%d\n", old_left, old_top, old_w, old_h);
}
*/
ass_be_priv_t* ass_be_init(void) {
ass_be_priv_t* priv;
priv = malloc(sizeof(ass_be_priv_t));
priv->size = 64*64;
priv->buf = malloc(64*64);
return priv;
}
int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur, int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur,
FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g,
bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius) bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius, ass_be_priv_t* be_priv, bitmap_t** bm_oo)
{ {
int bord = be ? (be+1) : 0; int bord = be ? (be/4+1) : 0;
bord = (blur_radius > 0.0) ? blur_radius : bord; blur_radius *= 2;
bord = (blur_radius > 0.0) ? (int)(blur_radius+3) : (int) bord;
assert(bm_g && bm_o && bm_s); assert(bm_g && bm_o && bm_s);
@ -278,28 +361,34 @@ int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur,
} }
} }
if (*bm_o) { if (*bm_o) {
resize_tmp(priv, (*bm_o)->w, (*bm_o)->h); //resize_tmp(priv, (*bm_o)->w, (*bm_o)->h);
resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h); resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h);
} }
resize_tmp(priv, (*bm_g)->w, (*bm_g)->h); //resize_tmp(priv, (*bm_g)->w, (*bm_g)->h);
resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h); resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h);
if (be) { if (be) {
while (be--) { while (be--) {
if (*bm_o) if (*bm_o) {
blur((*bm_o)->buffer, priv->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv->gt2, priv->g_r, priv->g_w); //blur((*bm_o)->buffer, priv->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
else be_blur((*bm_o)->buffer, be_priv, (*bm_o)->w, (*bm_o)->h);
blur((*bm_g)->buffer, priv->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv->gt2, priv->g_r, priv->g_w); //(*bm_o)->top--;
//(*bm_o)->left--;
} else
//blur((*bm_g)->buffer, priv->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
be_blur((*bm_g)->buffer, be_priv, (*bm_g)->w, (*bm_g)->h);
} }
} else } else {
if (blur_radius > 0.0) { if (blur_radius > 0.0) {
generate_tables(priv_blur, blur_radius); generate_tables(priv_blur, blur_radius);
if (*bm_o) if (*bm_o)
blur((*bm_o)->buffer, priv_blur->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w); blur((*bm_o)->buffer, priv_blur->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w);
else else
blur((*bm_g)->buffer, priv_blur->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w); blur((*bm_g)->buffer, priv_blur->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w);
} }
}
if (*bm_o) if (*bm_o)
*bm_s = fix_outline_and_shadow(*bm_g, *bm_o); *bm_s = fix_outline_and_shadow(*bm_g, *bm_o);
else else

View file

@ -23,11 +23,15 @@
#ifndef LIBASS_BITMAP_H #ifndef LIBASS_BITMAP_H
#define LIBASS_BITMAP_H #define LIBASS_BITMAP_H
#define MAX_BOXBLUR 50
#include <ft2build.h> #include <ft2build.h>
#include FT_GLYPH_H #include FT_GLYPH_H
typedef struct ass_synth_priv_s ass_synth_priv_t; typedef struct ass_synth_priv_s ass_synth_priv_t;
typedef struct ass_be_priv_s ass_be_priv_t;
ass_be_priv_t* ass_be_init(void);
ass_synth_priv_t* ass_synth_init(double); ass_synth_priv_t* ass_synth_init(double);
void ass_synth_done(ass_synth_priv_t* priv); void ass_synth_done(ass_synth_priv_t* priv);
@ -46,8 +50,10 @@ typedef struct bitmap_s {
* \param bm_g out: pointer to the bitmap of glyph shadow is returned here * \param bm_g out: pointer to the bitmap of glyph shadow is returned here
* \param be 1 = produces blurred bitmaps, 0 = normal bitmaps * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
*/ */
int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius); int glyph_to_bitmap(ass_synth_priv_t* priv, ass_synth_priv_t* priv_blur, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius, ass_be_priv_t* be_priv, bitmap_t** bm_oo);
void ass_free_bitmap(bitmap_t* bm); void ass_free_bitmap(bitmap_t* bm);
bitmap_t* alloc_bitmap(int w, int h);
#endif /* LIBASS_BITMAP_H */ #endif /* LIBASS_BITMAP_H */

View file

@ -41,11 +41,13 @@
#include "ass_fontconfig.h" #include "ass_fontconfig.h"
#include "ass_library.h" #include "ass_library.h"
#define MAX_GLYPHS 1000 #define MAX_GLYPHS 3000
#define MAX_LINES 100 #define MAX_LINES 300
#define BE_RADIUS 1.5 #define BE_RADIUS 1.5
#define BLUR_MAX_RADIUS 50.0 #define BLUR_MAX_RADIUS 50.0
#define NEAREST(x) ((int) (x + 0.5))
static int last_render_id = 0; static int last_render_id = 0;
typedef struct ass_settings_s { typedef struct ass_settings_s {
@ -83,12 +85,15 @@ struct ass_renderer_s {
int render_id; int render_id;
ass_synth_priv_t* synth_priv; ass_synth_priv_t* synth_priv;
ass_synth_priv_t* synth_priv_blur; ass_synth_priv_t* synth_priv_blur;
ass_be_priv_t* be_priv;
ass_image_t* images_root; // rendering result is stored here ass_image_t* images_root; // rendering result is stored here
ass_image_t* prev_images_root; ass_image_t* prev_images_root;
event_images_t* eimg; // temporary buffer for sorting rendered events event_images_t* eimg; // temporary buffer for sorting rendered events
int eimg_size; // allocated buffer size int eimg_size; // allocated buffer size
bitmap_t* bm_oo; // pointer to last rendered outline for compositing
}; };
typedef enum {EF_NONE = 0, EF_KARAOKE, EF_KARAOKE_KF, EF_KARAOKE_KO} effect_t; typedef enum {EF_NONE = 0, EF_KARAOKE, EF_KARAOKE_KF, EF_KARAOKE_KO} effect_t;
@ -116,7 +121,7 @@ typedef struct glyph_info_s {
// int height; // int height;
int be; // blur edges int be; // blur edges
double blur; // gaussian blur double blur; // gaussian blur
int shadow; double shadow;
double frx, fry, frz; // rotation double frx, fry, frz; // rotation
bitmap_hash_key_t hash_key; bitmap_hash_key_t hash_key;
@ -132,6 +137,9 @@ typedef struct text_info_s {
line_info_t lines[MAX_LINES]; line_info_t lines[MAX_LINES];
int n_lines; int n_lines;
int height; int height;
// Free list for composited glyphs
void* free_list[MAX_GLYPHS];
int free_count;
} text_info_t; } text_info_t;
@ -165,7 +173,7 @@ typedef struct render_context_s {
uint32_t fade; // alpha from \fad uint32_t fade; // alpha from \fad
char be; // blur edges char be; // blur edges
double blur; // gaussian blur double blur; // gaussian blur
int shadow; double shadow;
int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags
effect_t effect_type; effect_t effect_type;
@ -265,6 +273,8 @@ ass_renderer_t* ass_renderer_init(ass_library_t* library)
priv->synth_priv = ass_synth_init(BE_RADIUS); priv->synth_priv = ass_synth_init(BE_RADIUS);
priv->synth_priv_blur = ass_synth_init(BLUR_MAX_RADIUS); priv->synth_priv_blur = ass_synth_init(BLUR_MAX_RADIUS);
priv->be_priv = ass_be_init();
priv->bm_oo = NULL;
priv->library = library; priv->library = library;
priv->ftlibrary = ft; priv->ftlibrary = ft;
@ -315,6 +325,8 @@ static ass_image_t* my_draw_bitmap(unsigned char* bitmap, int bitmap_w, int bitm
img->color = color; img->color = color;
img->dst_x = dst_x; img->dst_x = dst_x;
img->dst_y = dst_y; img->dst_y = dst_y;
//printf("img dest %dx%d\n", dst_x, dst_y);
return img; return img;
} }
@ -398,6 +410,74 @@ static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t c
return tail; return tail;
} }
// Glyph compositing
static void render_overlap(ass_image_t** last_tail, ass_image_t** tail, void** free_list, int* free_count) {
int left, top, bottom, right;
int old_left, old_top, old_w, old_h;
int cur_left, cur_top, cur_w, cur_h;
int x, y, opos, cpos;
char m;
int ax = (*last_tail)->dst_x;
int ay = (*last_tail)->dst_y;
int aw = (*last_tail)->w;
int ah = (*last_tail)->h;
int bx = (*tail)->dst_x;
int by = (*tail)->dst_y;
int bw = (*tail)->w;
int bh = (*tail)->h;
unsigned char* a;
unsigned char* b;
// Calculate overlap as coordinates
left = (ax > bx) ? ax : bx;
top = (ay > by) ? ay : by;
right = ((ax+aw) < (bx+bw)) ?
(ax+aw) : (bx+bw);
bottom = ((ay+ah) < (by+bh)) ?
(ay+ah) : (by+bh);
// Check whether overlap rect is valid
if ((right <= left) || (bottom <= top))
return;
//printf("coord overlap %dx%d+%dx%d\n", left, top, right, bottom);
// Translate into coordinates+width/height for each bitmap
old_left = left-(ax);
old_top = top-(ay);
old_w = right-left;
old_h = bottom-top;
//printf("bitmap overlap %dx%d+%dx%d\n", old_left, old_top, old_w, old_h);
cur_left = left-(bx);
cur_top = top-(by);
cur_w = right-left;
cur_h = bottom-top;
//printf("bitmap overlap %dx%d+%dx%d\n\n", cur_left, cur_top, cur_w, cur_h);
// Allocate new bitmaps and copy over data
a = (*last_tail)->bitmap;
b = (*tail)->bitmap;
(*last_tail)->bitmap = malloc(aw*ah);
free_list[(*free_count)++] = (*last_tail)->bitmap;
(*tail)->bitmap = malloc(bw*bh);
free_list[(*free_count)++] = (*tail)->bitmap;
memcpy((*last_tail)->bitmap, a, aw*ah);
memcpy((*tail)->bitmap, b, bw*bh);
// Composite overlapping area
for (y=0; y<old_h; y++)
for (x=0; x<old_w; x++) {
opos = (old_top+y)*(aw) + (old_left+x);
cpos = (cur_top+y)*(bw) + (cur_left+x);
//printf("opos %d cpos %d\n", opos, cpos);
m = (a[opos] > b[cpos]) ?
a[opos] : b[cpos];
(*last_tail)->bitmap[opos] = 0;
(*tail)->bitmap[cpos] = m;
}
}
/** /**
* \brief Convert text_info_t struct to ass_image_t list * \brief Convert text_info_t struct to ass_image_t list
* Splits glyphs in halves when needed (for \kf karaoke). * Splits glyphs in halves when needed (for \kf karaoke).
@ -409,14 +489,16 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
bitmap_t* bm; bitmap_t* bm;
ass_image_t* head; ass_image_t* head;
ass_image_t** tail = &head; ass_image_t** tail = &head;
ass_image_t** last_tail = 0;
ass_image_t** here_tail = 0;
for (i = 0; i < text_info->length; ++i) { for (i = 0; i < text_info->length; ++i) {
glyph_info_t* info = text_info->glyphs + i; glyph_info_t* info = text_info->glyphs + i;
if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0)) if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0))
continue; continue;
pen_x = dst_x + info->pos.x + info->shadow; pen_x = dst_x + info->pos.x + NEAREST(info->shadow);
pen_y = dst_y + info->pos.y + info->shadow; pen_y = dst_y + info->pos.y + NEAREST(info->shadow);
bm = info->bm_s; bm = info->bm_s;
tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail); tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail);
@ -429,12 +511,23 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
pen_x = dst_x + info->pos.x; pen_x = dst_x + info->pos.x;
pen_y = dst_y + info->pos.y; pen_y = dst_y + info->pos.y;
bm = info->bm_o; bm = info->bm_o;
if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) { if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) {
// do nothing // do nothing
} else } else {
here_tail = tail;
tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail); tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail);
// Composite overlapping translucent outlines together
// Additional bitmaps not stored in cache are allocated for that
// These are put into a free list which gets freed either
// when a new frame starts or when the renderer is dealloc'd
if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0)) {
render_overlap(last_tail, here_tail, text_info->free_list, &text_info->free_count);
}
last_tail = here_tail;
}
} }
for (i = 0; i < text_info->length; ++i) { for (i = 0; i < text_info->length; ++i) {
glyph_info_t* info = text_info->glyphs + i; glyph_info_t* info = text_info->glyphs + i;
@ -455,7 +548,6 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
} else } else
tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail); tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail);
} }
*tail = 0; *tail = 0;
return head; return head;
} }
@ -583,7 +675,7 @@ static void change_border(double border)
if (border < 0) { if (border < 0) {
if (render_context.style->BorderStyle == 1) { if (render_context.style->BorderStyle == 1) {
if (render_context.style->Outline == 0 && render_context.style->Shadow > 0) if (render_context.style->Outline == 0 && render_context.style->Shadow > 0)
border = 1.; border = 0.0; //1.;
else else
border = render_context.style->Outline; border = render_context.style->Outline;
} else } else
@ -693,7 +785,7 @@ static char* parse_tag(char* p, double pwr) {
skip('\\'); skip('\\');
if ((*p == '}') || (*p == 0)) if ((*p == '}') || (*p == 0))
return p; return p;
// New tags introduced in vsfilter 2.39 // New tags introduced in vsfilter 2.39
if (mystrcmp(&p, "xbord")) { if (mystrcmp(&p, "xbord")) {
double val; double val;
@ -740,7 +832,6 @@ static char* parse_tag(char* p, double pwr) {
render_context.blur = val; render_context.blur = val;
} else } else
render_context.blur = 0.0; render_context.blur = 0.0;
// ASS standard tags // ASS standard tags
} else if (mystrcmp(&p, "fsc")) { } else if (mystrcmp(&p, "fsc")) {
char tp = *p++; char tp = *p++;
@ -785,18 +876,24 @@ static char* parse_tag(char* p, double pwr) {
double x, y; double x, y;
double k; double k;
skip('('); skip('(');
x1 = strtol(p, &p, 10); //x1 = strtol(p, &p, 10);
mystrtoi(&p, 10, &x1);
skip(','); skip(',');
y1 = strtol(p, &p, 10); //y1 = strtol(p, &p, 10);
mystrtoi(&p, 10, &y1);
skip(','); skip(',');
x2 = strtol(p, &p, 10); //x2 = strtol(p, &p, 10);
mystrtoi(&p, 10, &x2);
skip(','); skip(',');
y2 = strtol(p, &p, 10); //y2 = strtol(p, &p, 10);
mystrtoi(&p, 10, &y2);
if (*p == ',') { if (*p == ',') {
skip(','); skip(',');
t1 = strtoll(p, &p, 10); //t1 = strtoll(p, &p, 10);
mystrtoll(&p, 10, &t1);
skip(','); skip(',');
t2 = strtoll(p, &p, 10); //t2 = strtoll(p, &p, 10);
mystrtoll(&p, 10, &t2);
mp_msg(MSGT_ASS, MSGL_DBG2, "movement6: (%d, %d) -> (%d, %d), (%" PRId64 " .. %" PRId64 ")\n", mp_msg(MSGT_ASS, MSGL_DBG2, "movement6: (%d, %d) -> (%d, %d), (%" PRId64 " .. %" PRId64 ")\n",
x1, y1, x2, y2, (int64_t)t1, (int64_t)t2); x1, y1, x2, y2, (int64_t)t1, (int64_t)t2);
} else { } else {
@ -890,9 +987,11 @@ static char* parse_tag(char* p, double pwr) {
} else if (mystrcmp(&p, "pos")) { } else if (mystrcmp(&p, "pos")) {
int v1, v2; int v1, v2;
skip('('); skip('(');
v1 = strtol(p, &p, 10); //v1 = strtol(p, &p, 10);
mystrtoi(&p, 10, &v1);
skip(','); skip(',');
v2 = strtol(p, &p, 10); //v2 = strtol(p, &p, 10);
mystrtoi(&p, 10, &v2);
skip(')'); skip(')');
mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%d, %d)\n", v1, v2); mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%d, %d)\n", v1, v2);
if (render_context.evt_type != EVENT_POSITIONED) { if (render_context.evt_type != EVENT_POSITIONED) {
@ -906,9 +1005,11 @@ static char* parse_tag(char* p, double pwr) {
long long t1, t2, t3, t4; long long t1, t2, t3, t4;
if (*p == 'e') ++p; // either \fad or \fade if (*p == 'e') ++p; // either \fad or \fade
skip('('); skip('(');
a1 = strtol(p, &p, 10); //a1 = strtol(p, &p, 10);
mystrtoi(&p, 10, &a1);
skip(','); skip(',');
a2 = strtol(p, &p, 10); //a2 = strtol(p, &p, 10);
mystrtoi(&p, 10, &a2);
if (*p == ')') { if (*p == ')') {
// 2-argument version (\fad, according to specs) // 2-argument version (\fad, according to specs)
// a1 and a2 are fade-in and fade-out durations // a1 and a2 are fade-in and fade-out durations
@ -923,24 +1024,31 @@ static char* parse_tag(char* p, double pwr) {
// 6-argument version (\fade) // 6-argument version (\fade)
// a1 and a2 (and a3) are opacity values // a1 and a2 (and a3) are opacity values
skip(','); skip(',');
a3 = strtol(p, &p, 10); //a3 = strtol(p, &p, 10);
mystrtoi(&p, 10, &a3);
skip(','); skip(',');
t1 = strtoll(p, &p, 10); //t1 = strtoll(p, &p, 10);
mystrtoll(&p, 10, &t1);
skip(','); skip(',');
t2 = strtoll(p, &p, 10); //t2 = strtoll(p, &p, 10);
mystrtoll(&p, 10, &t2);
skip(','); skip(',');
t3 = strtoll(p, &p, 10); //t3 = strtoll(p, &p, 10);
mystrtoll(&p, 10, &t3);
skip(','); skip(',');
t4 = strtoll(p, &p, 10); //t4 = strtoll(p, &p, 10);
mystrtoll(&p, 10, &t4);
} }
skip(')'); skip(')');
render_context.fade = interpolate_alpha(frame_context.time - render_context.event->Start, t1, t2, t3, t4, a1, a2, a3); render_context.fade = interpolate_alpha(frame_context.time - render_context.event->Start, t1, t2, t3, t4, a1, a2, a3);
} else if (mystrcmp(&p, "org")) { } else if (mystrcmp(&p, "org")) {
int v1, v2; int v1, v2;
skip('('); skip('(');
v1 = strtol(p, &p, 10); //v1 = strtol(p, &p, 10);
mystrtoi(&p, 10, &v1);
skip(','); skip(',');
v2 = strtol(p, &p, 10); //v2 = strtol(p, &p, 10);
mystrtoi(&p, 10, &v2);
skip(')'); skip(')');
mp_msg(MSGT_ASS, MSGL_DBG2, "org(%d, %d)\n", v1, v2); mp_msg(MSGT_ASS, MSGL_DBG2, "org(%d, %d)\n", v1, v2);
// render_context.evt_type = EVENT_POSITIONED; // render_context.evt_type = EVENT_POSITIONED;
@ -1046,7 +1154,7 @@ static char* parse_tag(char* p, double pwr) {
if (mystrtoi(&p, 10, &val)) { if (mystrtoi(&p, 10, &val)) {
// Clamp to 10, since high values need excessive CPU // Clamp to 10, since high values need excessive CPU
val = (val < 0) ? 0 : val; val = (val < 0) ? 0 : val;
val = (val > 10) ? 10 : val; val = (val > 50) ? 10 : val;
render_context.be = val; render_context.be = val;
} else } else
render_context.be = 0; render_context.be = 0;
@ -1067,33 +1175,41 @@ static char* parse_tag(char* p, double pwr) {
render_context.italic = render_context.style->Italic; render_context.italic = render_context.style->Italic;
update_font(); update_font();
} else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) { } else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) {
int val = strtol(p, &p, 10); //int val = strtol(p, &p, 10);
int val = 0;
mystrtoi(&p, 10, &val);
render_context.effect_type = EF_KARAOKE_KF; render_context.effect_type = EF_KARAOKE_KF;
if (render_context.effect_timing) if (render_context.effect_timing)
render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_skip_timing += render_context.effect_timing;
render_context.effect_timing = val * 10; render_context.effect_timing = val * 10;
} else if (mystrcmp(&p, "ko")) { } else if (mystrcmp(&p, "ko")) {
int val = strtol(p, &p, 10); //int val = strtol(p, &p, 10);
int val = 0;
mystrtoi(&p, 10, &val);
render_context.effect_type = EF_KARAOKE_KO; render_context.effect_type = EF_KARAOKE_KO;
if (render_context.effect_timing) if (render_context.effect_timing)
render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_skip_timing += render_context.effect_timing;
render_context.effect_timing = val * 10; render_context.effect_timing = val * 10;
} else if (mystrcmp(&p, "k")) { } else if (mystrcmp(&p, "k")) {
int val = strtol(p, &p, 10); //int val = strtol(p, &p, 10);
int val = 0;
mystrtoi(&p, 10, &val);
render_context.effect_type = EF_KARAOKE; render_context.effect_type = EF_KARAOKE;
if (render_context.effect_timing) if (render_context.effect_timing)
render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_skip_timing += render_context.effect_timing;
render_context.effect_timing = val * 10; render_context.effect_timing = val * 10;
} else if (mystrcmp(&p, "shad")) { } else if (mystrcmp(&p, "shad")) {
int val; int val = 0;;
if (mystrtoi(&p, 10, &val)) if (mystrtoi(&p, 10, &val))
render_context.shadow = val; render_context.shadow = val;
else else
render_context.shadow = render_context.style->Shadow; render_context.shadow = render_context.style->Shadow;
} else if (mystrcmp(&p, "pbo")) { } else if (mystrcmp(&p, "pbo")) {
(void)strtol(p, &p, 10); // ignored //(void)strtol(p, &p, 10); // ignored
int val = 0;
mystrtoi(&p, 10, &val);
} else if (mystrcmp(&p, "p")) { } else if (mystrcmp(&p, "p")) {
int val; int val = 0;
if (!mystrtoi(&p, 10, &val)) if (!mystrtoi(&p, 10, &val))
val = 0; val = 0;
render_context.drawing_mode = !!val; render_context.drawing_mode = !!val;
@ -1148,7 +1264,7 @@ static unsigned get_next_char(char** str)
return ' '; return ' ';
} }
} }
chr = utf8_get_char(&p); chr = utf8_get_char((const char **) &p);
*str = p; *str = p;
return chr; return chr;
} }
@ -1386,7 +1502,7 @@ static void get_bitmap_glyph(glyph_info_t* info)
ass_renderer->synth_priv_blur, ass_renderer->synth_priv_blur,
info->glyph, info->outline_glyph, info->glyph, info->outline_glyph,
&info->bm, &info->bm_o, &info->bm, &info->bm_o,
&info->bm_s, info->be, info->blur); &info->bm_s, info->be, info->blur, ass_renderer->be_priv, &ass_renderer->bm_oo);
if (error) if (error)
info->symbol = 0; info->symbol = 0;
@ -1402,6 +1518,21 @@ static void get_bitmap_glyph(glyph_info_t* info)
FT_Done_Glyph(info->glyph); FT_Done_Glyph(info->glyph);
if (info->outline_glyph) if (info->outline_glyph)
FT_Done_Glyph(info->outline_glyph); FT_Done_Glyph(info->outline_glyph);
/*
// Find outline overlap rectangle and composite glyphs together
if (ass_renderer->bm_oo) {
printf("current outline %dx%d+%dx%d\n",
info->bm_o->left, info->bm_o->top,
info->bm_o->w, info->bm_o->h);
printf("old outline %dx%d+%dx%d\n",
ass_renderer->bm_oo->left, ass_renderer->bm_oo->top,
ass_renderer->bm_oo->w, ass_renderer->bm_oo->h);
get_overlap(info->bm_o, ass_renderer->bm_oo);
printf("--\n");
}
ass_renderer->bm_oo = info->bm_o;
*/
} }
/** /**
@ -2047,7 +2178,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
center.x = x2scr(render_context.org_x); center.x = x2scr(render_context.org_x);
center.y = y2scr(render_context.org_y); center.y = y2scr(render_context.org_y);
} else { } else {
int bx, by; int bx = 0, by = 0;
get_base_point(bbox, alignment, &bx, &by); get_base_point(bbox, alignment, &bx, &by);
center.x = device_x + bx; center.x = device_x + bx;
center.y = device_y + by; center.y = device_y + by;
@ -2195,14 +2326,21 @@ int ass_set_fonts_nofc(ass_renderer_t* priv, const char* default_font, const cha
*/ */
static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long now) static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long now)
{ {
int i = 0;
ass_renderer = priv; ass_renderer = priv;
global_settings = &priv->settings; global_settings = &priv->settings;
if (!priv->settings.frame_width && !priv->settings.frame_height) if (!priv->settings.frame_width && !priv->settings.frame_height)
return 1; // library not initialized return 1; // library not initialized
if (track->n_events == 0) if (track->n_events == 0)
return 1; // nothing to do return 1; // nothing to do
// Free composited images
while (text_info.free_count--)
free(text_info.free_list[i++]);
text_info.free_count = 0;
frame_context.ass_priv = priv; frame_context.ass_priv = priv;
frame_context.width = global_settings->frame_width; frame_context.width = global_settings->frame_width;
@ -2231,6 +2369,7 @@ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long n
priv->prev_images_root = priv->images_root; priv->prev_images_root = priv->images_root;
priv->images_root = 0; priv->images_root = 0;
return 0; return 0;
} }

View file

@ -32,8 +32,23 @@
int mystrtoi(char** p, int base, int* res) int mystrtoi(char** p, int base, int* res)
{ {
// NOTE: base argument is ignored, but not used anyway
double temp_res;
char* start = *p; char* start = *p;
*res = strtol(*p, p, base); temp_res = strtod(*p, p);
*res = (int) (temp_res + 0.5);
//printf("read %f, rounded to %d\n", temp_res, *res);
if (*p != start) return 1;
else return 0;
}
int mystrtoll(char** p, int base, long long* res)
{
// NOTE: base argument is ignored, but not used anyway
double temp_res;
char* start = *p;
temp_res = strtod(*p, p);
*res = (long long) (temp_res + 0.5);
if (*p != start) return 1; if (*p != start) return 1;
else return 0; else return 0;
} }

View file

@ -26,6 +26,7 @@
#include <stdint.h> #include <stdint.h>
int mystrtoi(char** p, int base, int* res); int mystrtoi(char** p, int base, int* res);
int mystrtoll(char** p, int base, long long* res);
int mystrtou32(char** p, int base, uint32_t* res); int mystrtou32(char** p, int base, uint32_t* res);
int mystrtod(char** p, double* res); int mystrtod(char** p, double* res);
int strtocolor(char** q, uint32_t* res); int strtocolor(char** q, uint32_t* res);