From 2c412cdab94a7bb27c5a1e04ab902295215de888 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Sat, 11 Jul 2009 02:18:51 +0200 Subject: [PATCH] Message callback funtionality Introduce functionality for providing a message callback that is used for passing messages to the controlling application instead of simply printing them to standard output. The function pointer to the callback is stored in the ass_library_t instance. ass_msg needs access to it, so in many places the library instance needs to be passed around now. The default behavior is the old one: messages of MSGL_INFO or lower are printed to the standard output, prefixed with "[ass]". --- libass/ass.c | 119 ++++++++++++++++++++++------------------ libass/ass.h | 4 ++ libass/ass_bitmap.c | 19 ++++--- libass/ass_bitmap.h | 10 ++-- libass/ass_cache.c | 35 +++++++----- libass/ass_cache.h | 12 ++-- libass/ass_drawing.c | 6 +- libass/ass_drawing.h | 1 + libass/ass_font.c | 32 ++++++----- libass/ass_fontconfig.c | 75 +++++++++++++------------ libass/ass_fontconfig.h | 7 ++- libass/ass_library.c | 28 +++++++++- libass/ass_library.h | 3 + libass/ass_render.c | 112 +++++++++++++++++++------------------ libass/ass_utils.c | 31 +++++------ libass/ass_utils.h | 13 +++-- libass/libass.sym | 1 + test/test.cpp | 11 ++++ 18 files changed, 308 insertions(+), 211 deletions(-) diff --git a/libass/ass.c b/libass/ass.c index 135232f..9eaa7b0 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -182,26 +182,26 @@ static int lookup_style(ass_track_t *track, char *name) return i; } i = track->default_style; - ass_msg(MSGL_WARN, + ass_msg(track->library, MSGL_WARN, "[%p]: Warning: no style named '%s' found, using '%s'", track, name, track->styles[i].Name); return i; // use the first style } -static uint32_t string2color(char *p) +static uint32_t string2color(ass_library_t *library, char *p) { uint32_t tmp; - (void) strtocolor(&p, &tmp); + (void) strtocolor(library, &p, &tmp); return tmp; } -static long long string2timecode(char *p) +static long long string2timecode(ass_library_t *library, char *p) { unsigned h, m, s, ms; long long tm; int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms); if (res < 4) { - ass_msg(MSGL_WARN, "Bad timestamp"); + ass_msg(library, MSGL_WARN, "Bad timestamp"); return 0; } tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10; @@ -229,22 +229,30 @@ static int numpad2align(int val) #define ANYVAL(name,func) \ } else if (strcasecmp(tname, #name) == 0) { \ target->name = func(token); \ - ass_msg(MSGL_DBG2, "%s = %s", #name, token); + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); #define STRVAL(name) \ } else if (strcasecmp(tname, #name) == 0) { \ if (target->name != NULL) free(target->name); \ target->name = strdup(token); \ - ass_msg(MSGL_DBG2, "%s = %s", #name, token); + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); + +#define COLORVAL(name) \ + } else if (strcasecmp(tname, #name) == 0) { \ + target->name = string2color(track->library, token); \ + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); -#define COLORVAL(name) ANYVAL(name,string2color) #define INTVAL(name) ANYVAL(name,atoi) #define FPVAL(name) ANYVAL(name,atof) -#define TIMEVAL(name) ANYVAL(name,string2timecode) +#define TIMEVAL(name) \ + } else if (strcasecmp(tname, #name) == 0) { \ + target->name = string2timecode(track->library, token); \ + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); + #define STYLEVAL(name) \ } else if (strcasecmp(tname, #name) == 0) { \ target->name = lookup_style(track, token); \ - ass_msg(MSGL_DBG2, "%s = %s", #name, token); + ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); #define ALIAS(alias,name) \ if (strcasecmp(tname, #alias) == 0) {tname = #name;} @@ -318,7 +326,7 @@ static int process_event_tail(ass_track_t *track, ass_event_t *event, if (last >= event->Text && *last == '\r') *last = 0; } - ass_msg(MSGL_DBG2, "Text = %s", event->Text); + ass_msg(track->library, MSGL_DBG2, "Text = %s", event->Text); event->Duration -= event->Start; free(format); return 0; // "Text" is always the last @@ -458,7 +466,7 @@ static int process_style(ass_track_t *track, char *str) q = format = strdup(track->style_format); - ass_msg(MSGL_V, "[%p] Style: %s", track, str); + ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str); sid = ass_alloc_style(track); @@ -535,7 +543,7 @@ static int process_styles_line(ass_track_t *track, char *str) char *p = str + 7; skip_spaces(&p); track->style_format = strdup(p); - ass_msg(MSGL_DBG2, "Style format: %s", + ass_msg(track->library, MSGL_DBG2, "Style format: %s", track->style_format); } else if (!strncmp(str, "Style:", 6)) { char *p = str + 6; @@ -565,14 +573,13 @@ static void event_format_fallback(ass_track_t *track) { track->parser_priv->state = PST_EVENTS; if (track->track_type == TRACK_TYPE_SSA) - track->event_format = - strdup - ("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"); + track->event_format = strdup("Format: Marked, Start, End, Style, " + "Name, MarginL, MarginR, MarginV, Effect, Text"); else - track->event_format = - strdup - ("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text"); - ass_msg(MSGL_V, "No event format found, using fallback"); + track->event_format = strdup("Format: Layer, Start, End, Style, " + "Actor, MarginL, MarginR, MarginV, Effect, Text"); + ass_msg(track->library, MSGL_V, + "No event format found, using fallback"); } static int process_events_line(ass_track_t *track, char *str) @@ -581,7 +588,7 @@ static int process_events_line(ass_track_t *track, char *str) char *p = str + 7; skip_spaces(&p); track->event_format = strdup(p); - ass_msg(MSGL_DBG2, "Event format: %s", track->event_format); + ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format); } else if (!strncmp(str, "Dialogue:", 9)) { // This should never be reached for embedded subtitles. // They have slightly different format and are parsed in ass_process_chunk, @@ -601,7 +608,7 @@ static int process_events_line(ass_track_t *track, char *str) process_event_tail(track, event, str, 0); } else { - ass_msg(MSGL_V, "Not understood: '%s'", str); + ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); } return 0; } @@ -636,11 +643,11 @@ static int decode_font(ass_track_t *track) int dsize; // decoded size unsigned char *buf = 0; - ass_msg(MSGL_V, "Font: %d bytes encoded data", - track->parser_priv->fontdata_used); + ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data", + track->parser_priv->fontdata_used); size = track->parser_priv->fontdata_used; if (size % 4 == 1) { - ass_msg(MSGL_ERR, "Bad encoded data size"); + ass_msg(track->library, MSGL_ERR, "Bad encoded data size"); goto error_decode_font; } buf = malloc(size / 4 * 3 + 2); @@ -686,19 +693,20 @@ static int process_fonts_line(ass_track_t *track, char *str) decode_font(track); } track->parser_priv->fontname = strdup(p); - ass_msg(MSGL_V, "Fontname: %s", + ass_msg(track->library, MSGL_V, "Fontname: %s", track->parser_priv->fontname); return 0; } if (!track->parser_priv->fontname) { - ass_msg(MSGL_V, "Not understood: '%s'", str); + ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); return 0; } len = strlen(str); if (len > 80) { - ass_msg(MSGL_WARN, "Font line too long: %d, %s", len, str); + ass_msg(track->library, MSGL_WARN, "Font line too long: %d, %s", + len, str); return 0; } if (track->parser_priv->fontdata_used + len > @@ -801,7 +809,7 @@ void ass_process_data(ass_track_t *track, char *data, int size) memcpy(str, data, size); str[size] = '\0'; - ass_msg(MSGL_V, "Event: %s", str); + ass_msg(track->library, MSGL_V, "Event: %s", str); process_text(track, str); free(str); } @@ -852,14 +860,14 @@ void ass_process_chunk(ass_track_t *track, char *data, int size, ass_event_t *event; if (!track->event_format) { - ass_msg(MSGL_WARN, "Event format header missing"); + ass_msg(track->library, MSGL_WARN, "Event format header missing"); return; } str = malloc(size + 1); memcpy(str, data, size); str[size] = '\0'; - ass_msg(MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s", + ass_msg(track->library, MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s", (int64_t) timecode, (int64_t) duration, str); eid = ass_alloc_event(track); @@ -898,7 +906,8 @@ void ass_process_chunk(ass_track_t *track, char *data, int size, * \param size buffer size * \return a pointer to recoded buffer, caller is responsible for freeing it **/ -static char *sub_recode(char *data, size_t size, char *codepage) +static char *sub_recode(ass_library_t *library, char *data, size_t size, + char *codepage) { iconv_t icdsc; char *tocp = "UTF-8"; @@ -913,14 +922,14 @@ static char *sub_recode(char *data, size_t size, char *codepage) || sscanf(codepage, "ENCA:%2s:%99s", enca_lang, enca_fallback) == 2) { cp_tmp = - ass_guess_buffer_cp((unsigned char *) data, size, enca_lang, - enca_fallback); + ass_guess_buffer_cp(library, (unsigned char *) data, size, + enca_lang, enca_fallback); } #endif if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) { - ass_msg(MSGL_V, "Opened iconv descriptor"); + ass_msg(library, MSGL_V, "Opened iconv descriptor"); } else - ass_msg(MSGL_ERR, "Error opening iconv descriptor"); + ass_msg(library, MSGL_ERR, "Error opening iconv descriptor"); } { @@ -951,7 +960,7 @@ static char *sub_recode(char *data, size_t size, char *codepage) osize += size; oleft += size; } else { - ass_msg(MSGL_WARN, "Error recoding file"); + ass_msg(library, MSGL_WARN, "Error recoding file"); return NULL; } } else if (clear) @@ -963,7 +972,7 @@ static char *sub_recode(char *data, size_t size, char *codepage) if (icdsc != (iconv_t) (-1)) { (void) iconv_close(icdsc); icdsc = (iconv_t) (-1); - ass_msg(MSGL_V, "Closed iconv descriptor"); + ass_msg(library, MSGL_V, "Closed iconv descriptor"); } return outbuf; @@ -976,7 +985,7 @@ static char *sub_recode(char *data, size_t size, char *codepage) * \param bufsize out: file size * \return pointer to file contents. Caller is responsible for its deallocation. */ -static char *read_file(char *fname, size_t *bufsize) +static char *read_file(ass_library_t *library, char *fname, size_t *bufsize) { int res; long sz; @@ -985,12 +994,14 @@ static char *read_file(char *fname, size_t *bufsize) FILE *fp = fopen(fname, "rb"); if (!fp) { - ass_msg(MSGL_WARN, "ass_read_file(%s): fopen failed", fname); + ass_msg(library, MSGL_WARN, + "ass_read_file(%s): fopen failed", fname); return 0; } res = fseek(fp, 0, SEEK_END); if (res == -1) { - ass_msg(MSGL_WARN, "ass_read_file(%s): fseek failed", fname); + ass_msg(library, MSGL_WARN, + "ass_read_file(%s): fseek failed", fname); fclose(fp); return 0; } @@ -999,14 +1010,14 @@ static char *read_file(char *fname, size_t *bufsize) rewind(fp); if (sz > 10 * 1024 * 1024) { - ass_msg(MSGL_INFO, + ass_msg(library, MSGL_INFO, "ass_read_file(%s): Refusing to load subtitles " "larger than 10MiB", fname); fclose(fp); return 0; } - ass_msg(MSGL_V, "File size: %ld", sz); + ass_msg(library, MSGL_V, "File size: %ld", sz); buf = malloc(sz + 1); assert(buf); @@ -1014,7 +1025,7 @@ static char *read_file(char *fname, size_t *bufsize) do { res = fread(buf + bytes_read, 1, sz - bytes_read, fp); if (res <= 0) { - ass_msg(MSGL_INFO, "Read failed, %d: %s", errno, + ass_msg(library, MSGL_INFO, "Read failed, %d: %s", errno, strerror(errno)); fclose(fp); free(buf); @@ -1080,7 +1091,7 @@ ass_track_t *ass_read_memory(ass_library_t *library, char *buf, #ifdef CONFIG_ICONV if (codepage) - buf = sub_recode(buf, bufsize, codepage); + buf = sub_recode(library, buf, bufsize, codepage); if (!buf) return 0; else @@ -1092,23 +1103,24 @@ ass_track_t *ass_read_memory(ass_library_t *library, char *buf, if (!track) return 0; - ass_msg(MSGL_INFO, "Added subtitle file: " + ass_msg(library, MSGL_INFO, "Added subtitle file: " " (%d styles, %d events)", track->n_styles, track->n_events); return track; } -static char *read_file_recode(char *fname, char *codepage, size_t *size) +static char *read_file_recode(ass_library_t *library, char *fname, + char *codepage, size_t *size) { char *buf; size_t bufsize; - buf = read_file(fname, &bufsize); + buf = read_file(library, fname, &bufsize); if (!buf) return 0; #ifdef CONFIG_ICONV if (codepage) { - char *tmpbuf = sub_recode(buf, bufsize, codepage); + char *tmpbuf = sub_recode(library, buf, bufsize, codepage); free(buf); buf = tmpbuf; } @@ -1133,7 +1145,7 @@ ass_track_t *ass_read_file(ass_library_t *library, char *fname, ass_track_t *track; size_t bufsize; - buf = read_file_recode(fname, codepage, &bufsize); + buf = read_file_recode(library, fname, codepage, &bufsize); if (!buf) return 0; track = parse_memory(library, buf); @@ -1143,7 +1155,8 @@ ass_track_t *ass_read_file(ass_library_t *library, char *fname, track->name = strdup(fname); - ass_msg(MSGL_INFO, "Added subtitle file: '%s' (%d styles, %d events)", + ass_msg(library, MSGL_INFO, + "Added subtitle file: '%s' (%d styles, %d events)", fname, track->n_styles, track->n_events); return track; @@ -1158,13 +1171,13 @@ int ass_read_styles(ass_track_t *track, char *fname, char *codepage) parser_state_t old_state; size_t sz; - buf = read_file(fname, &sz); + buf = read_file(track->library, fname, &sz); if (!buf) return 1; #ifdef CONFIG_ICONV if (codepage) { char *tmpbuf; - tmpbuf = sub_recode(buf, sz, codepage); + tmpbuf = sub_recode(track->library, buf, sz, codepage); free(buf); buf = tmpbuf; } diff --git a/libass/ass.h b/libass/ass.h index d911e99..e0160d6 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -22,6 +22,7 @@ #define LIBASS_ASS_H #include +#include #include "ass_types.h" /// Libass renderer object. Contents are private. @@ -69,6 +70,9 @@ void ass_set_style_overrides(ass_library_t *priv, char **list); void ass_process_force_style(ass_track_t *track); +void ass_set_message_cb(ass_library_t *priv, + void (*msg_cb)(int, char *, va_list *)); + /** * \brief initialize the renderer * \param priv library handle diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index a72caad..c8cd8be 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -165,7 +165,7 @@ static bitmap_t *copy_bitmap(const bitmap_t *src) return dst; } -static int check_glyph_area(FT_Glyph glyph) +static int check_glyph_area(ass_library_t *library, FT_Glyph glyph) { FT_BBox bbox; long long dx, dy; @@ -173,14 +173,15 @@ static int check_glyph_area(FT_Glyph glyph) dx = bbox.xMax - bbox.xMin; dy = bbox.yMax - bbox.yMin; if (dx * dy > 8000000) { - ass_msg(MSGL_WARN, "Glyph bounding box too large: %dx%dpx", + ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx", (int) dx, (int) dy); return 1; } else return 0; } -static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord) +static bitmap_t *glyph_to_bitmap_internal(ass_library_t *library, + FT_Glyph glyph, int bord) { FT_BitmapGlyph bg; FT_Bitmap *bit; @@ -191,11 +192,11 @@ static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord) int i; int error; - if (check_glyph_area(glyph)) + if (check_glyph_area(library, glyph)) return 0; error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0); if (error) { - ass_msg(MSGL_WARN, "FT_Glyph_To_Bitmap error %d", + ass_msg(library, MSGL_WARN, "FT_Glyph_To_Bitmap error %d", error); return 0; } @@ -203,7 +204,7 @@ static bitmap_t *glyph_to_bitmap_internal(FT_Glyph glyph, int bord) bg = (FT_BitmapGlyph) glyph; bit = &(bg->bitmap); if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) { - ass_msg(MSGL_WARN, "Unsupported pixel mode: %d", + ass_msg(library, MSGL_WARN, "Unsupported pixel mode: %d", (int) (bit->pixel_mode)); FT_Done_Glyph(glyph); return 0; @@ -471,7 +472,7 @@ static void be_blur(unsigned char *buf, int w, int h) } } -int glyph_to_bitmap(ass_synth_priv_t *priv_blur, +int glyph_to_bitmap(ass_library_t *library, 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, FT_Vector shadow_offset) @@ -487,12 +488,12 @@ int glyph_to_bitmap(ass_synth_priv_t *priv_blur, *bm_g = *bm_o = *bm_s = 0; if (glyph) - *bm_g = glyph_to_bitmap_internal(glyph, bord); + *bm_g = glyph_to_bitmap_internal(library, glyph, bord); if (!*bm_g) return 1; if (outline_glyph) { - *bm_o = glyph_to_bitmap_internal(outline_glyph, bord); + *bm_o = glyph_to_bitmap_internal(library, outline_glyph, bord); if (!*bm_o) { ass_free_bitmap(*bm_g); return 1; diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index f6b1380..2e34a5c 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -24,6 +24,8 @@ #include #include FT_GLYPH_H +#include "ass.h" + typedef struct ass_synth_priv_s ass_synth_priv_t; ass_synth_priv_t *ass_synth_init(double); @@ -44,10 +46,10 @@ typedef struct bitmap_s { * \param bm_g out: pointer to the bitmap of glyph shadow is returned here * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps */ -int glyph_to_bitmap(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, FT_Vector shadow_offset); +int glyph_to_bitmap(ass_library_t *library, 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, FT_Vector shadow_offset); void ass_free_bitmap(bitmap_t *bm); diff --git a/libass/ass_cache.c b/libass/ass_cache.c index adee0cc..ed44a2f 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -51,12 +51,14 @@ static void hashmap_item_dtor(void *key, size_t key_size, void *value, free(value); } -hashmap_t *hashmap_init(size_t key_size, size_t value_size, int nbuckets, +hashmap_t *hashmap_init(ass_library_t *library, size_t key_size, + size_t value_size, int nbuckets, hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare, hashmap_hash_t hash) { hashmap_t *map = calloc(1, sizeof(hashmap_t)); + map->library = library; map->nbuckets = nbuckets; map->key_size = key_size; map->value_size = value_size; @@ -72,7 +74,7 @@ void hashmap_done(hashmap_t *map) int i; // print stats if (map->count > 0 || map->hit_count + map->miss_count > 0) - ass_msg(MSGL_V, + ass_msg(map->library, MSGL_V, "cache statistics: \n total accesses: %d\n hits: %d\n " "misses: %d\n object count: %d", map->hit_count + map->miss_count, map->hit_count, @@ -179,10 +181,10 @@ void *ass_font_cache_add(hashmap_t *font_cache, ass_font_t *font) return hashmap_insert(font_cache, &(font->desc), font); } -hashmap_t *ass_font_cache_init(void) +hashmap_t *ass_font_cache_init(ass_library_t *library) { hashmap_t *font_cache; - font_cache = hashmap_init(sizeof(ass_font_desc_t), + font_cache = hashmap_init(library, sizeof(ass_font_desc_t), sizeof(ass_font_t), 1000, font_hash_dtor, font_compare, font_desc_hash); @@ -235,10 +237,11 @@ bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache, return hashmap_find(bitmap_cache, key); } -hashmap_t *ass_bitmap_cache_init(void) +hashmap_t *ass_bitmap_cache_init(ass_library_t *library) { hashmap_t *bitmap_cache; - bitmap_cache = hashmap_init(sizeof(bitmap_hash_key_t), + bitmap_cache = hashmap_init(library, + sizeof(bitmap_hash_key_t), sizeof(bitmap_hash_val_t), 0xFFFF + 13, bitmap_hash_dtor, bitmap_compare, @@ -253,8 +256,10 @@ void ass_bitmap_cache_done(hashmap_t *bitmap_cache) hashmap_t *ass_bitmap_cache_reset(hashmap_t *bitmap_cache) { + ass_library_t *lib = bitmap_cache->library; + ass_bitmap_cache_done(bitmap_cache); - return ass_bitmap_cache_init(); + return ass_bitmap_cache_init(lib); } //--------------------------------- @@ -289,10 +294,10 @@ glyph_hash_val_t *cache_find_glyph(hashmap_t *glyph_cache, return hashmap_find(glyph_cache, key); } -hashmap_t *ass_glyph_cache_init(void) +hashmap_t *ass_glyph_cache_init(ass_library_t *library) { hashmap_t *glyph_cache; - glyph_cache = hashmap_init(sizeof(glyph_hash_key_t), + glyph_cache = hashmap_init(library, sizeof(glyph_hash_key_t), sizeof(glyph_hash_val_t), 0xFFFF + 13, glyph_hash_dtor, glyph_compare, glyph_hash); @@ -306,8 +311,10 @@ void ass_glyph_cache_done(hashmap_t *glyph_cache) hashmap_t *ass_glyph_cache_reset(hashmap_t *glyph_cache) { + ass_library_t *lib = glyph_cache->library; + ass_glyph_cache_done(glyph_cache); - return ass_glyph_cache_init(); + return ass_glyph_cache_init(lib); } @@ -342,10 +349,10 @@ composite_hash_val_t *cache_find_composite(hashmap_t *composite_cache, return hashmap_find(composite_cache, key); } -hashmap_t *ass_composite_cache_init(void) +hashmap_t *ass_composite_cache_init(ass_library_t *library) { hashmap_t *composite_cache; - composite_cache = hashmap_init(sizeof(composite_hash_key_t), + composite_cache = hashmap_init(library, sizeof(composite_hash_key_t), sizeof(composite_hash_val_t), 0xFFFF + 13, composite_hash_dtor, composite_compare, @@ -360,6 +367,8 @@ void ass_composite_cache_done(hashmap_t *composite_cache) hashmap_t *ass_composite_cache_reset(hashmap_t *composite_cache) { + ass_library_t *lib = composite_cache->library; + ass_composite_cache_done(composite_cache); - return ass_composite_cache_init(); + return ass_composite_cache_init(lib); } diff --git a/libass/ass_cache.h b/libass/ass_cache.h index d8de97a..004a4b6 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -49,9 +49,11 @@ typedef struct hashmap_s { int hit_count; int miss_count; int count; + ass_library_t *library; } hashmap_t; -hashmap_t *hashmap_init(size_t key_size, size_t value_size, int nbuckets, +hashmap_t *hashmap_init(ass_library_t *library, size_t key_size, + size_t value_size, int nbuckets, hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare, hashmap_hash_t hash); @@ -59,7 +61,7 @@ void hashmap_done(hashmap_t *map); void *hashmap_insert(hashmap_t *map, void *key, void *value); void *hashmap_find(hashmap_t *map, void *key); -hashmap_t *ass_font_cache_init(void); +hashmap_t *ass_font_cache_init(ass_library_t *library); ass_font_t *ass_font_cache_find(hashmap_t *, ass_font_desc_t *desc); void *ass_font_cache_add(hashmap_t *, ass_font_t *font); void ass_font_cache_done(hashmap_t *); @@ -74,7 +76,7 @@ typedef struct bitmap_hash_val_s { bitmap_t *bm_s; } bitmap_hash_val_t; -hashmap_t *ass_bitmap_cache_init(void); +hashmap_t *ass_bitmap_cache_init(ass_library_t *library); void *cache_add_bitmap(hashmap_t *, bitmap_hash_key_t *key, bitmap_hash_val_t *val); bitmap_hash_val_t *cache_find_bitmap(hashmap_t *bitmap_cache, @@ -88,7 +90,7 @@ typedef struct composite_hash_val_s { unsigned char *b; } composite_hash_val_t; -hashmap_t *ass_composite_cache_init(void); +hashmap_t *ass_composite_cache_init(ass_library_t *library); void *cache_add_composite(hashmap_t *, composite_hash_key_t *key, composite_hash_val_t *val); composite_hash_val_t *cache_find_composite(hashmap_t *composite_cache, @@ -105,7 +107,7 @@ typedef struct glyph_hash_val_s { int asc, desc; // ascender/descender of a drawing } glyph_hash_val_t; -hashmap_t *ass_glyph_cache_init(void); +hashmap_t *ass_glyph_cache_init(ass_library_t *library); void *cache_add_glyph(hashmap_t *, glyph_hash_key_t *key, glyph_hash_val_t *val); glyph_hash_val_t *cache_find_glyph(hashmap_t *glyph_cache, diff --git a/libass/ass_drawing.c b/libass/ass_drawing.c index c05a962..f75bbd9 100644 --- a/libass/ass_drawing.c +++ b/libass/ass_drawing.c @@ -139,8 +139,9 @@ static void drawing_finish(ass_drawing_t *drawing) for (i = 0; i < ol->n_points; i++) ol->points[i].y += offset; - ass_msg(MSGL_V, "Parsed drawing with %d points and %d contours", - ol->n_points, ol->n_contours); + ass_msg(drawing->library, MSGL_V, + "Parsed drawing with %d points and %d contours", ol->n_points, + ol->n_contours); } /* @@ -364,6 +365,7 @@ ass_drawing_t *ass_drawing_new(void *fontconfig_priv, ass_font_t *font, drawing->size = DRAWING_INITIAL_SIZE; drawing->ftlibrary = lib; + drawing->library = font->library; drawing_make_glyph(drawing, fontconfig_priv, font, hint); drawing->scale_x = 1.; diff --git a/libass/ass_drawing.h b/libass/ass_drawing.h index 323c05d..dfd68f0 100644 --- a/libass/ass_drawing.h +++ b/libass/ass_drawing.h @@ -58,6 +58,7 @@ typedef struct ass_drawing_s { // private FT_Library ftlibrary; // FT library instance, needed for font ops + ass_library_t *library; int size; // current buffer size ass_drawing_token_t *tokens; // tokenized drawing int max_points; // current maximum size diff --git a/libass/ass_font.c b/libass/ass_font.c index 76c4793..34ae292 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -39,7 +39,7 @@ * Select Microfost Unicode CharMap, if the font has one. * Otherwise, let FreeType decide. */ -static void charmap_magic(FT_Face face) +static void charmap_magic(ass_library_t *library, FT_Face face) { int i; for (i = 0; i < face->num_charmaps; ++i) { @@ -56,10 +56,11 @@ static void charmap_magic(FT_Face face) if (!face->charmap) { if (face->num_charmaps == 0) { - ass_msg(MSGL_WARN, "Font face with no charmaps"); + ass_msg(library, MSGL_WARN, "Font face with no charmaps"); return; } - ass_msg(MSGL_WARN, "No charmap autodetected, trying the first one"); + ass_msg(library, MSGL_WARN, + "No charmap autodetected, trying the first one"); FT_Set_Charmap(face, face->charmaps[0]); return; } @@ -125,7 +126,7 @@ static int add_face(void *fc_priv, ass_font_t *font, uint32_t ch) return -1; path = - fontconfig_select(fc_priv, font->desc.family, + fontconfig_select(font->library, fc_priv, font->desc.family, font->desc.treat_family_as_pattern, font->desc.bold, font->desc.italic, &index, ch); if (!path) @@ -140,19 +141,21 @@ static int add_face(void *fc_priv, ass_font_t *font, uint32_t ch) font->library->fontdata[mem_idx].size, 0, &face); if (error) { - ass_msg(MSGL_WARN, "Error opening memory font: '%s'", path); + ass_msg(font->library, MSGL_WARN, + "Error opening memory font: '%s'", path); free(path); return -1; } } else { error = FT_New_Face(font->ftlibrary, path, index, &face); if (error) { - ass_msg(MSGL_WARN, "Error opening font: '%s', %d", path, index); + ass_msg(font->library, MSGL_WARN, + "Error opening font: '%s', %d", path, index); free(path); return -1; } } - charmap_magic(face); + charmap_magic(font->library, face); buggy_font_workaround(face); font->faces[font->n_faces++] = face; @@ -384,7 +387,7 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, #ifdef CONFIG_FONTCONFIG if (index == 0) { int face_idx; - ass_msg(MSGL_INFO, + ass_msg(font->library, MSGL_INFO, "Glyph 0x%X not found, selecting one more " "font for (%s, %d, %d)", ch, font->desc.family, font->desc.bold, font->desc.italic); @@ -393,9 +396,10 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, face = font->faces[face_idx]; index = FT_Get_Char_Index(face, ch); if (index == 0) { - ass_msg(MSGL_ERR, "Glyph 0x%X not found in font " - "for (%s, %d, %d)", ch, font->desc.family, - font->desc.bold, font->desc.italic); + ass_msg(font->library, MSGL_ERR, + "Glyph 0x%X not found in font for (%s, %d, %d)", + ch, font->desc.family, font->desc.bold, + font->desc.italic); } } } @@ -418,7 +422,8 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags); if (error) { - ass_msg(MSGL_WARN, "Error loading glyph, index %d", index); + ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", + index); return 0; } #if (FREETYPE_MAJOR > 2) || \ @@ -432,7 +437,8 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ass_font_t *font, #endif error = FT_Get_Glyph(face->glyph, &glyph); if (error) { - ass_msg(MSGL_WARN, "Error loading glyph, index %d", index); + ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", + index); return 0; } diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c index e23c4f2..d8d64e2 100644 --- a/libass/ass_fontconfig.c +++ b/libass/ass_fontconfig.c @@ -71,9 +71,10 @@ struct fc_instance_s { * \param code: the character that should be present in the font, can be 0 * \return font file path */ -static char *_select_font(fc_instance_t *priv, const char *family, - int treat_family_as_pattern, unsigned bold, - unsigned italic, int *index, uint32_t code) +static char *_select_font(ass_library_t *library, fc_instance_t *priv, + const char *family, int treat_family_as_pattern, + unsigned bold, unsigned italic, int *index, + uint32_t code) { FcBool rc; FcResult result; @@ -193,7 +194,7 @@ static char *_select_font(fc_instance_t *priv, const char *family, if (!treat_family_as_pattern && !(r_family && strcasecmp((const char *) r_family, family) == 0) && !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) - ass_msg(MSGL_WARN, + ass_msg(library, MSGL_WARN, "fontconfig: Selected font is not the requested one: " "'%s' != '%s'", (const char *) (r_fullname ? r_fullname : r_family), family); @@ -214,7 +215,7 @@ static char *_select_font(fc_instance_t *priv, const char *family, if (result != FcResultMatch) r_embolden = 0; - ass_msg(MSGL_V, + ass_msg(library, MSGL_V, "Font info: family '%s', style '%s', fullname '%s'," " slant %d, weight %d%s", (const char *) r_family, (const char *) r_style, (const char *) r_fullname, r_slant, @@ -241,9 +242,10 @@ static char *_select_font(fc_instance_t *priv, const char *family, * \param code: the character that should be present in the font, can be 0 * \return font file path */ -char *fontconfig_select(fc_instance_t *priv, const char *family, - int treat_family_as_pattern, unsigned bold, - unsigned italic, int *index, uint32_t code) +char *fontconfig_select(ass_library_t *library, fc_instance_t *priv, + const char *family, int treat_family_as_pattern, + unsigned bold, unsigned italic, int *index, + uint32_t code) { char *res = 0; if (!priv->config) { @@ -252,33 +254,34 @@ char *fontconfig_select(fc_instance_t *priv, const char *family, } if (family && *family) res = - _select_font(priv, family, treat_family_as_pattern, bold, - italic, index, code); + _select_font(library, priv, family, treat_family_as_pattern, + bold, italic, index, code); if (!res && priv->family_default) { res = - _select_font(priv, priv->family_default, 0, bold, italic, index, - code); + _select_font(library, priv, priv->family_default, 0, bold, + italic, index, code); if (res) - ass_msg(MSGL_WARN, "fontconfig_select: Using default font " - "family: (%s, %d, %d) -> %s, %d", + ass_msg(library, MSGL_WARN, "fontconfig_select: Using default " + "font family: (%s, %d, %d) -> %s, %d", family, bold, italic, res, *index); } if (!res && priv->path_default) { res = priv->path_default; *index = priv->index_default; - ass_msg(MSGL_WARN, "fontconfig_select: Using default font: " + ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: " "(%s, %d, %d) -> %s, %d", family, bold, italic, res, *index); } if (!res) { - res = _select_font(priv, "Arial", 0, bold, italic, index, code); + res = _select_font(library, priv, "Arial", 0, bold, italic, + index, code); if (res) - ass_msg(MSGL_WARN, "fontconfig_select: Using 'Arial' font " - "family: (%s, %d, %d) -> %s, %d", family, bold, italic, - res, *index); + ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' " + "font family: (%s, %d, %d) -> %s, %d", family, bold, + italic, res, *index); } if (res) - ass_msg(MSGL_V, + ass_msg(library, MSGL_V, "fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold, italic, res, *index); return res; @@ -354,11 +357,11 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library, res = mkdir(fonts_dir); #endif if (res) { - ass_msg(MSGL_WARN, "Failed to create directory '%s'", + ass_msg(library, MSGL_WARN, "Failed to create directory '%s'", fonts_dir); } } else if (!S_ISDIR(st.st_mode)) { - ass_msg(MSGL_WARN, "Not a directory: '%s'", fonts_dir); + ass_msg(library, MSGL_WARN, "Not a directory: '%s'", fonts_dir); } fname = validate_fname((char *) name); @@ -384,7 +387,7 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library, rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data, data_size, face_index, &face); if (rc) { - ass_msg(MSGL_WARN, "Error opening memory font: %s", + ass_msg(library, MSGL_WARN, "Error opening memory font: %s", name); return; } @@ -394,21 +397,21 @@ static void process_fontdata(fc_instance_t *priv, ass_library_t *library, FcFreeTypeQueryFace(face, (unsigned char *) name, 0, FcConfigGetBlanks(priv->config)); if (!pattern) { - ass_msg(MSGL_WARN, "%s failed", "FcFreeTypeQueryFace"); + ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace"); FT_Done_Face(face); return; } fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication if (!fset) { - ass_msg(MSGL_WARN, "%s failed", "FcConfigGetFonts"); + ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts"); FT_Done_Face(face); return; } res = FcFontSetAdd(fset, pattern); if (!res) { - ass_msg(MSGL_WARN, "%s failed", "FcFontSetAdd"); + ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd"); FT_Done_Face(face); return; } @@ -436,7 +439,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, int i; if (!fc) { - ass_msg(MSGL_WARN, + ass_msg(library, MSGL_WARN, "Fontconfig disabled, only default font will be used."); goto exit; } @@ -454,7 +457,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, } if (!rc || !priv->config) { - ass_msg(MSGL_FATAL, "%s failed", "FcInitLoadConfigAndFonts"); + ass_msg(library, MSGL_FATAL, "%s failed", "FcInitLoadConfigAndFonts"); goto exit; } @@ -463,10 +466,10 @@ fc_instance_t *fontconfig_init(ass_library_t *library, if (dir) { if (FcDirCacheValid((const FcChar8 *) dir) == FcFalse) { - ass_msg(MSGL_INFO, "Updating font cache"); + ass_msg(library, MSGL_INFO, "Updating font cache"); if (FcGetVersion() >= 20390 && FcGetVersion() < 20400) - ass_msg(MSGL_WARN, "Beta versions of fontconfig are not " - "supported. Update before reporting any bugs"); + ass_msg(library, MSGL_WARN, "Beta versions of fontconfig" + "are not supported. Update before reporting any bugs"); // FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir() if (FcGetVersion() < 20390) { FcFontSet *fcs; @@ -475,7 +478,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, fss = FcStrSetCreate(); rc = FcStrSetAdd(fss, (const FcChar8 *) dir); if (!rc) { - ass_msg(MSGL_WARN, "%s failed", "FcStrSetAdd"); + ass_msg(library, MSGL_WARN, "%s failed", "FcStrSetAdd"); goto ErrorFontCache; } @@ -483,13 +486,13 @@ fc_instance_t *fontconfig_init(ass_library_t *library, FcConfigGetBlanks(priv->config), (const FcChar8 *) dir, FcFalse); if (!rc) { - ass_msg(MSGL_WARN, "%s failed", "FcDirScan"); + ass_msg(library, MSGL_WARN, "%s failed", "FcDirScan"); goto ErrorFontCache; } rc = FcDirSave(fcs, fss, (const FcChar8 *) dir); if (!rc) { - ass_msg(MSGL_WARN, "%s failed", "FcDirSave"); + ass_msg(library, MSGL_WARN, "%s failed", "FcDirSave"); goto ErrorFontCache; } ErrorFontCache: @@ -499,7 +502,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); if (!rc) { - ass_msg(MSGL_WARN, "%s failed", "FcConfigAppFontAddDir"); + ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir"); } } @@ -527,7 +530,7 @@ fc_instance_t *fontconfig_init(ass_library_t *library, { fc_instance_t *priv; - ass_msg(MSGL_WARN, + ass_msg(library, MSGL_WARN, "Fontconfig disabled, only default font will be used."); priv = calloc(1, sizeof(fc_instance_t)); diff --git a/libass/ass_fontconfig.h b/libass/ass_fontconfig.h index 71b2006..53441cc 100644 --- a/libass/ass_fontconfig.h +++ b/libass/ass_fontconfig.h @@ -35,9 +35,10 @@ typedef struct fc_instance_s fc_instance_t; fc_instance_t *fontconfig_init(ass_library_t *library, FT_Library ftlibrary, const char *family, const char *path, int fc, const char *config); -char *fontconfig_select(fc_instance_t *priv, const char *family, - int treat_family_as_pattern, unsigned bold, - unsigned italic, int *index, uint32_t code); +char *fontconfig_select(ass_library_t *library, fc_instance_t *priv, + const char *family, int treat_family_as_pattern, + unsigned bold, unsigned italic, int *index, + uint32_t code); void fontconfig_done(fc_instance_t *priv); #endif /* LIBASS_FONTCONFIG_H */ diff --git a/libass/ass_library.c b/libass/ass_library.c index ce877da..2a8f5b2 100644 --- a/libass/ass_library.c +++ b/libass/ass_library.c @@ -22,14 +22,27 @@ #include #include #include +#include #include "ass.h" #include "ass_library.h" +#include "ass_utils.h" +static void ass_msg_handler(int level, char *fmt, va_list *va) +{ + if (level > MSGL_INFO) + return; + printf("[ass] "); + vprintf(fmt, *va); + printf("\n"); +} ass_library_t *ass_library_init(void) { - return calloc(1, sizeof(ass_library_t)); + ass_library_t* lib = calloc(1, sizeof(ass_library_t)); + lib->msg_callback = ass_msg_handler; + + return lib; } void ass_library_done(ass_library_t *priv) @@ -114,3 +127,16 @@ void ass_clear_fonts(ass_library_t *priv) priv->fontdata = NULL; priv->num_fontdata = 0; } + +/* + * Register a message callback function with libass. Without setting one, + * a default handler is used which prints everything with MSGL_INFO or + * higher to the standard output. + */ +void ass_set_message_cb(ass_library_t *priv, + void (*msg_cb)(int, char *, va_list *)) +{ + if (msg_cb) + priv->msg_callback = msg_cb; +} + diff --git a/libass/ass_library.h b/libass/ass_library.h index 48ffefe..a73dd6c 100644 --- a/libass/ass_library.h +++ b/libass/ass_library.h @@ -21,6 +21,8 @@ #ifndef LIBASS_LIBRARY_H #define LIBASS_LIBRARY_H +#include + typedef struct ass_fontdata_s { char *name; char *data; @@ -34,6 +36,7 @@ struct ass_library_s { ass_fontdata_t *fontdata; int num_fontdata; + void (*msg_callback)(int, char *, va_list *); }; #endif /* LIBASS_LIBRARY_H */ diff --git a/libass/ass_render.c b/libass/ass_render.c index c5d7d06..ccd7bd5 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -245,7 +245,7 @@ static void ass_lazy_track_init(ass_renderer_t *render_priv) if (track->PlayResX && track->PlayResY) return; if (!track->PlayResX && !track->PlayResY) { - ass_msg(MSGL_WARN, + ass_msg(render_priv->library, MSGL_WARN, "Neither PlayResX nor PlayResY defined. Assuming 384x288"); track->PlayResX = 384; track->PlayResY = 288; @@ -256,19 +256,19 @@ static void ass_lazy_track_init(ass_renderer_t *render_priv) render_priv->width; if (!track->PlayResY && track->PlayResX == 1280) { track->PlayResY = 1024; - ass_msg(MSGL_WARN, + ass_msg(render_priv->library, MSGL_WARN, "PlayResY undefined, setting to %d", track->PlayResY); } else if (!track->PlayResY) { track->PlayResY = track->PlayResX / orig_aspect + .5; - ass_msg(MSGL_WARN, + ass_msg(render_priv->library, MSGL_WARN, "PlayResY undefined, setting to %d", track->PlayResY); } else if (!track->PlayResX && track->PlayResY == 1024) { track->PlayResX = 1280; - ass_msg(MSGL_WARN, + ass_msg(render_priv->library, MSGL_WARN, "PlayResX undefined, setting to %d", track->PlayResX); } else if (!track->PlayResX) { track->PlayResX = track->PlayResY * orig_aspect + .5; - ass_msg(MSGL_WARN, + ass_msg(render_priv->library, MSGL_WARN, "PlayResX undefined, setting to %d", track->PlayResX); } } @@ -283,14 +283,14 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library) error = FT_Init_FreeType(&ft); if (error) { - ass_msg(MSGL_FATAL, "%s failed", "FT_Init_FreeType"); + ass_msg(library, MSGL_FATAL, "%s failed", "FT_Init_FreeType"); goto ass_init_exit; } FT_Library_Version(ft, &vmajor, &vminor, &vpatch); - ass_msg(MSGL_V, "FreeType library version: %d.%d.%d", + ass_msg(library, MSGL_V, "FreeType library version: %d.%d.%d", vmajor, vminor, vpatch); - ass_msg(MSGL_V, "FreeType headers version: %d.%d.%d", + ass_msg(library, MSGL_V, "FreeType headers version: %d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH); priv = calloc(1, sizeof(ass_renderer_t)); @@ -305,10 +305,10 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library) priv->ftlibrary = ft; // images_root and related stuff is zero-filled in calloc - priv->cache.font_cache = ass_font_cache_init(); - priv->cache.bitmap_cache = ass_bitmap_cache_init(); - priv->cache.composite_cache = ass_composite_cache_init(); - priv->cache.glyph_cache = ass_glyph_cache_init(); + priv->cache.font_cache = ass_font_cache_init(library); + priv->cache.bitmap_cache = ass_bitmap_cache_init(library); + priv->cache.composite_cache = ass_composite_cache_init(library); + priv->cache.glyph_cache = ass_glyph_cache_init(library); priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL; priv->text_info.max_lines = MAX_LINES_INITIAL; @@ -318,9 +318,9 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library) ass_init_exit: if (priv) - ass_msg(MSGL_INFO, "Init"); + ass_msg(library, MSGL_INFO, "Init"); else - ass_msg(MSGL_ERR, "Init failed"); + ass_msg(library, MSGL_ERR, "Init failed"); return priv; } @@ -527,22 +527,22 @@ static ass_image_t **render_glyph(ass_renderer_t *render_priv, tmp = dst_x - clip_x0; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip left"); + ass_msg(render_priv->library, MSGL_DBG2, "clip left"); b_x0 = -tmp; } tmp = dst_y - clip_y0; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip top"); + ass_msg(render_priv->library, MSGL_DBG2, "clip top"); b_y0 = -tmp; } tmp = clip_x1 - dst_x - bm->w; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip right"); + ass_msg(render_priv->library, MSGL_DBG2, "clip right"); b_x1 = bm->w + tmp; } tmp = clip_y1 - dst_y - bm->h; if (tmp < 0) { - ass_msg(MSGL_DBG2, "clip bottom"); + ass_msg(render_priv->library, MSGL_DBG2, "clip bottom"); b_y1 = bm->h + tmp; } @@ -939,7 +939,8 @@ static void change_border(ass_renderer_t *render_priv, double border_x, memory, &render_priv->state.stroker); #endif if (error) { - ass_msg(MSGL_V, "failed to get stroker"); + ass_msg(render_priv->library, MSGL_V, + "failed to get stroker"); render_priv->state.stroker = 0; } } @@ -1172,14 +1173,14 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) mystrtoll(&p, &t1); skip(','); mystrtoll(&p, &t2); - ass_msg(MSGL_DBG2, + ass_msg(render_priv->library, MSGL_DBG2, "movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %" PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1, (int64_t) t2); } else { t1 = 0; t2 = render_priv->state.event->Duration; - ass_msg(MSGL_DBG2, + ass_msg(render_priv->library, MSGL_DBG2, "movement: (%f, %f) -> (%f, %f)", x1, y1, x2, y2); } skip(')'); @@ -1241,7 +1242,7 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) } else if (mystrcmp(&p, "alpha")) { uint32_t val; int i; - if (strtocolor(&p, &val)) { + if (strtocolor(render_priv->library, &p, &val)) { unsigned char a = val >> 24; for (i = 0; i < 4; ++i) change_alpha(&render_priv->state.c[i], a, pwr); @@ -1260,12 +1261,12 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) int val; if (mystrtoi(&p, &val) && val) { int v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment - ass_msg(MSGL_DBG2, "an %d", val); + ass_msg(render_priv->library, MSGL_DBG2, "an %d", val); if (v != 0) v = 3 - v; val = ((val - 1) % 3) + 1; // horizontal alignment val += v * 4; - ass_msg(MSGL_DBG2, "align %d", val); + ass_msg(render_priv->library, MSGL_DBG2, "align %d", val); render_priv->state.alignment = val; } else render_priv->state.alignment = @@ -1284,9 +1285,9 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) skip(','); mystrtod(&p, &v2); skip(')'); - ass_msg(MSGL_DBG2, "pos(%f, %f)", v1, v2); + ass_msg(render_priv->library, MSGL_DBG2, "pos(%f, %f)", v1, v2); if (render_priv->state.evt_type == EVENT_POSITIONED) { - ass_msg(MSGL_V, "Subtitle has a new \\pos " + ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos " "after \\move or \\pos, ignoring"); } else { render_priv->state.evt_type = EVENT_POSITIONED; @@ -1339,7 +1340,7 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) skip(','); mystrtoi(&p, &v2); skip(')'); - ass_msg(MSGL_DBG2, "org(%d, %d)", v1, v2); + ass_msg(render_priv->library, MSGL_DBG2, "org(%d, %d)", v1, v2); if (!render_priv->state.have_origin) { render_priv->state.org_x = v1; render_priv->state.org_y = v2; @@ -1425,9 +1426,9 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) } } else if (mystrcmp(&p, "c")) { uint32_t val; - if (!strtocolor(&p, &val)) + if (!strtocolor(render_priv->library, &p, &val)) val = render_priv->state.style->PrimaryColour; - ass_msg(MSGL_DBG2, "color: %X", val); + ass_msg(render_priv->library, MSGL_DBG2, "color: %X", val); change_color(&render_priv->state.c[0], val, pwr); } else if ((*p >= '1') && (*p <= '4') && (++p) && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) { @@ -1436,7 +1437,7 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) char cmd = *(p - 1); uint32_t val; assert((n >= '1') && (n <= '4')); - if (!strtocolor(&p, &val)) + if (!strtocolor(render_priv->library, &p, &val)) switch (n) { case '1': val = render_priv->state.style->PrimaryColour; @@ -1462,10 +1463,11 @@ static char *parse_tag(ass_renderer_t *render_priv, char *p, double pwr) change_alpha(render_priv->state.c + cidx, val >> 24, pwr); break; default: - ass_msg(MSGL_WARN, "Bad command: %c%c", n, cmd); + ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c", + n, cmd); break; } - ass_msg(MSGL_DBG2, "single c/a at %f: %c%c = %X", + ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X", pwr, n, cmd, render_priv->state.c[cidx]); } else if (mystrcmp(&p, "r")) { reset_render_context(render_priv); @@ -1579,7 +1581,8 @@ static unsigned get_next_char(ass_renderer_t *render_priv, char **str) } else break; } else if (*p != '\\') - ass_msg(MSGL_V, "Unable to parse: '%s'", p); + ass_msg(render_priv->library, MSGL_V, + "Unable to parse: '%s'", p); if (*p == 0) break; } @@ -1625,8 +1628,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event) if (strncmp(event->Effect, "Banner;", 7) == 0) { int delay; if (cnt < 1) { - ass_msg(MSGL_V, "Error parsing effect: '%s'", - event->Effect); + ass_msg(render_priv->library, MSGL_V, + "Error parsing effect: '%s'", event->Effect); return; } if (cnt >= 2 && v[1] == 0) // right-to-left @@ -1648,8 +1651,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event) } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { render_priv->state.scroll_direction = SCROLL_TB; } else { - ass_msg(MSGL_V, "Unknown transition effect: '%s'", - event->Effect); + ass_msg(render_priv->library, MSGL_V, + "Unknown transition effect: '%s'", event->Effect); return; } // parse scroll up/down parameters @@ -1657,8 +1660,8 @@ apply_transition_effects(ass_renderer_t *render_priv, ass_event_t *event) int delay; int y0, y1; if (cnt < 3) { - ass_msg(MSGL_V, "Error parsing effect: '%s'", - event->Effect); + ass_msg(render_priv->library, MSGL_V, + "Error parsing effect: '%s'", event->Effect); return; } delay = v[2]; @@ -1864,7 +1867,8 @@ static void stroke_outline_glyph(ass_renderer_t *render_priv, error = FT_Glyph_StrokeBorder((FT_Glyph *) glyph, render_priv->state.stroker, 0, 1); if (error) - ass_msg(MSGL_WARN, "FT_Glyph_Stroke error: %d", error); + ass_msg(render_priv->library, MSGL_WARN, + "FT_Glyph_Stroke error: %d", error); // "Stroke" with the outline emboldener in two passes. // The outlines look uglier, but the emboldening never adds any points @@ -2036,7 +2040,8 @@ get_bitmap_glyph(ass_renderer_t *render_priv, glyph_info_t *info) -info->hash_key.advance.y); // render glyph - error = glyph_to_bitmap(render_priv->synth_priv, + error = glyph_to_bitmap(render_priv->library, + render_priv->synth_priv, info->glyph, info->outline_glyph, &info->bm, &info->bm_o, &info->bm_s, info->be, @@ -2133,8 +2138,8 @@ wrap_lines_smart(ass_renderer_t *render_priv, double max_text_width) if (cur->symbol == '\n') { break_type = 2; break_at = i; - ass_msg(MSGL_DBG2, "forced line break at %d", - break_at); + ass_msg(render_priv->library, MSGL_DBG2, + "forced line break at %d", break_at); } if ((len >= max_text_width) @@ -2145,8 +2150,9 @@ wrap_lines_smart(ass_renderer_t *render_priv, double max_text_width) break_at = i - 1; if (break_at == -1) break_at = 0; - ass_msg(MSGL_DBG2, "overfill at %d", i); - ass_msg(MSGL_DBG2, "line break at %d", break_at); + ass_msg(render_priv->library, MSGL_DBG2, "overfill at %d", i); + ass_msg(render_priv->library, MSGL_DBG2, "line break at %d", + break_at); } if (break_at != -1) { @@ -2245,7 +2251,7 @@ wrap_lines_smart(ass_renderer_t *render_priv, double max_text_width) cur_line++; pen_shift_x = d6_to_double(-cur->pos.x); pen_shift_y += height + render_priv->settings.line_spacing; - ass_msg(MSGL_DBG2, + ass_msg(render_priv->library, MSGL_DBG2, "shifting from %d to %d by (%f, %f)", i, text_info->length - 1, pen_shift_x, pen_shift_y); } @@ -2310,7 +2316,8 @@ static void process_karaoke_effects(ass_renderer_t *render_priv) dt /= (tm_end - tm_start); x = x_start + (x_end - x_start) * dt; } else { - ass_msg(MSGL_ERR, "Unknown effect type"); + ass_msg(render_priv->library, MSGL_ERR, + "Unknown effect type"); continue; } @@ -2463,11 +2470,11 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, ass_drawing_t *drawing; if (event->Style >= render_priv->track->n_styles) { - ass_msg(MSGL_WARN, "No style found"); + ass_msg(render_priv->library, MSGL_WARN, "No style found"); return 1; } if (!event->Text) { - ass_msg(MSGL_WARN, "Empty event"); + ass_msg(render_priv->library, MSGL_WARN, "Empty event"); return 1; } @@ -2767,7 +2774,7 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, } else { // subtitle double scr_y; if (valign != VALIGN_SUB) - ass_msg(MSGL_V, + ass_msg(render_priv->library, MSGL_V, "Invalid valign, supposing 0 (subtitle)"); scr_y = y2scr_sub(render_priv, @@ -2793,7 +2800,7 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event, if (render_priv->state.evt_type == EVENT_POSITIONED) { double base_x = 0; double base_y = 0; - ass_msg(MSGL_DBG2, "positioned event at %f, %f", + ass_msg(render_priv->library, MSGL_DBG2, "positioned event at %f, %f", render_priv->state.pos_x, render_priv->state.pos_y); get_base_point(&bbox, alignment, &base_x, &base_y); device_x = @@ -3174,7 +3181,8 @@ fix_collisions(ass_renderer_t *render_priv, event_images_t *imgs, int cnt) s.a = priv->top; s.b = priv->top + priv->height; if (priv->height != imgs[i].height) { // no, it's not - ass_msg(MSGL_WARN, "Warning! Event height has changed"); + ass_msg(render_priv->library, MSGL_WARN, + "Warning! Event height has changed"); priv->top = 0; priv->height = 0; } diff --git a/libass/ass_utils.c b/libass/ass_utils.c index 6e45b02..0592d33 100644 --- a/libass/ass_utils.c +++ b/libass/ass_utils.c @@ -21,10 +21,13 @@ #include "config.h" #include +#include #include #include #include FT_GLYPH_H +#include "ass_library.h" +#include "ass.h" #include "ass_utils.h" int mystrtoi(char **p, int *res) @@ -71,7 +74,7 @@ int mystrtod(char **p, double *res) return 0; } -int strtocolor(char **q, uint32_t *res) +int strtocolor(ass_library_t *library, char **q, uint32_t *res) { uint32_t color = 0; int result; @@ -80,7 +83,7 @@ int strtocolor(char **q, uint32_t *res) if (*p == '&') ++p; else - ass_msg(MSGL_DBG2, "suspicious color format: \"%s\"\n", p); + ass_msg(library, MSGL_DBG2, "suspicious color format: \"%s\"\n", p); if (*p == 'H' || *p == 'h') { ++p; @@ -119,15 +122,11 @@ char parse_bool(char *str) return 0; } -void ass_msg(int lvl, char *fmt, ...) +void ass_msg(ass_library_t *priv, int lvl, char *fmt, ...) { va_list va; - if (lvl > MSGL_INFO) - return; va_start(va, fmt); - printf("[ass] "); - vprintf(fmt, va); - printf("\n"); + priv->msg_callback(lvl, fmt, &va); va_end(va); } @@ -162,8 +161,9 @@ unsigned ass_utf8_get_char(char **str) } #ifdef CONFIG_ENCA -void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, - char *preferred_language, char *fallback) +void *ass_guess_buffer_cp(ass_library_t *library, unsigned char *buffer, + int buflen, char *preferred_language, + char *fallback) { const char **languages; size_t langcnt; @@ -173,11 +173,10 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, int i; languages = enca_get_languages(&langcnt); - ass_msg(MSGL_V, "ENCA supported languages: "); + ass_msg(library, MSGL_V, "ENCA supported languages"); for (i = 0; i < langcnt; i++) { - ass_msg(MSGL_V, "%s ", languages[i]); + ass_msg(library, MSGL_V, "lang %s", languages[i]); } - ass_msg(MSGL_V, "\n"); for (i = 0; i < langcnt; i++) { const char *tmp; @@ -189,7 +188,7 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, tmp = enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV); if (tmp && encoding.charset != ENCA_CS_UNKNOWN) { detected_sub_cp = strdup(tmp); - ass_msg(MSGL_INFO, "ENCA detected charset: %s\n", tmp); + ass_msg(library, MSGL_INFO, "ENCA detected charset: %s", tmp); } enca_analyser_free(analyser); } @@ -198,8 +197,8 @@ void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, if (!detected_sub_cp) { detected_sub_cp = strdup(fallback); - ass_msg(MSGL_INFO, - "ENCA detection failed: fallback to %s\n", fallback); + ass_msg(library, MSGL_INFO, + "ENCA detection failed: fallback to %s", fallback); } return detected_sub_cp; diff --git a/libass/ass_utils.h b/libass/ass_utils.h index efcf883..a906ca5 100644 --- a/libass/ass_utils.h +++ b/libass/ass_utils.h @@ -32,6 +32,8 @@ #include #endif +#include "ass.h" + #define MSGL_FATAL 0 #define MSGL_ERR 1 #define MSGL_WARN 2 @@ -46,12 +48,15 @@ int mystrtoi(char **p, int *res); int mystrtoll(char **p, long long *res); int mystrtou32(char **p, int base, uint32_t *res); int mystrtod(char **p, double *res); -int strtocolor(char **q, uint32_t *res); +int strtocolor(ass_library_t *library, char **q, uint32_t *res); char parse_bool(char *str); unsigned ass_utf8_get_char(char **str); -void ass_msg(int lvl, char *fmt, ...); -void *ass_guess_buffer_cp(unsigned char *buffer, int buflen, - char *preferred_language, char *fallback); +void ass_msg(ass_library_t *priv, int lvl, char *fmt, ...); +#ifdef CONFIG_ENCA +void *ass_guess_buffer_cp(ass_library_t *library, unsigned char *buffer, + int buflen, char *preferred_language, + char *fallback); +#endif static inline int d6_to_int(int x) { diff --git a/libass/libass.sym b/libass/libass.sym index 7579b4f..5cb1c40 100644 --- a/libass/libass.sym +++ b/libass/libass.sym @@ -30,3 +30,4 @@ ass_add_font ass_clear_fonts ass_step_sub ass_process_force_style +ass_set_message_cb diff --git a/test/test.cpp b/test/test.cpp index 816d779..9728590 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include extern "C" { #include @@ -16,6 +17,15 @@ struct image_t { ass_library_t* ass_library; ass_renderer_t* ass_renderer; +void msg_callback(int level, char *fmt, va_list *va) +{ + if (level > 6) + return; + printf("libass: "); + vprintf(fmt, *va); + printf("\n"); +} + static void write_png(char *fname, image_t* img) { FILE * fp; @@ -71,6 +81,7 @@ static void init(int frame_w, int frame_h) { ass_set_fonts_dir(ass_library, ""); ass_set_extract_fonts(ass_library, 0); ass_set_style_overrides(ass_library, NULL); + ass_set_message_cb(ass_library, msg_callback); ass_renderer = ass_renderer_init(ass_library); if (!ass_renderer) throw std::runtime_error("ass_renderer_init failed"); -- 2.40.0