[MPlayer-cvslog] r36459 - in trunk/libass: ass.c ass.h ass_bitmap.c ass_bitmap.h ass_font.c ass_fontconfig.c ass_parse.c ass_render.c ass_render.h ass_render_api.c ass_shaper.c ass_types.h ass_utils.c ass_utils.h
reimar
subversion at mplayerhq.hu
Tue Sep 24 22:50:02 CEST 2013
Author: reimar
Date: Tue Sep 24 22:50:02 2013
New Revision: 36459
Log:
Update libass to latest git version.
Modified:
trunk/libass/ass.c
trunk/libass/ass.h
trunk/libass/ass_bitmap.c
trunk/libass/ass_bitmap.h
trunk/libass/ass_font.c
trunk/libass/ass_fontconfig.c
trunk/libass/ass_parse.c
trunk/libass/ass_render.c
trunk/libass/ass_render.h
trunk/libass/ass_render_api.c
trunk/libass/ass_shaper.c
trunk/libass/ass_types.h
trunk/libass/ass_utils.c
trunk/libass/ass_utils.h
Modified: trunk/libass/ass.c
==============================================================================
--- trunk/libass/ass.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -387,6 +387,8 @@ void ass_process_force_style(ASS_Track *
track->ScaledBorderAndShadow = parse_bool(token);
else if (!strcasecmp(*fs, "Kerning"))
track->Kerning = parse_bool(token);
+ else if (!strcasecmp(*fs, "YCbCr Matrix"))
+ track->YCbCrMatrix = parse_ycbcr_matrix(token);
dt = strrchr(*fs, '.');
if (dt) {
@@ -424,6 +426,7 @@ void ass_process_force_style(ASS_Track *
FPVAL(ScaleY)
FPVAL(Outline)
FPVAL(Shadow)
+ FPVAL(Blur)
}
}
}
@@ -514,7 +517,7 @@ static int process_style(ASS_Track *trac
INTVAL(Underline)
INTVAL(StrikeOut)
FPVAL(Spacing)
- INTVAL(Angle)
+ FPVAL(Angle)
INTVAL(BorderStyle)
INTVAL(Alignment)
if (track->track_type == TRACK_TYPE_ASS)
@@ -573,6 +576,8 @@ static int process_info_line(ASS_Track *
track->ScaledBorderAndShadow = parse_bool(str + 22);
} else if (!strncmp(str, "Kerning:", 8)) {
track->Kerning = parse_bool(str + 8);
+ } else if (!strncmp(str, "YCbCr Matrix:", 13)) {
+ track->YCbCrMatrix = parse_ycbcr_matrix(str + 13);
} else if (!strncmp(str, "Language:", 9)) {
char *p = str + 9;
while (*p && isspace(*p)) p++;
@@ -587,10 +592,10 @@ static void event_format_fallback(ASS_Tr
{
track->parser_priv->state = PST_EVENTS;
if (track->track_type == TRACK_TYPE_SSA)
- track->event_format = strdup("Format: Marked, Start, End, Style, "
+ track->event_format = strdup("Marked, Start, End, Style, "
"Name, MarginL, MarginR, MarginV, Effect, Text");
else
- track->event_format = strdup("Format: Layer, Start, End, Style, "
+ track->event_format = strdup("Layer, Start, End, Style, "
"Actor, MarginL, MarginR, MarginV, Effect, Text");
ass_msg(track->library, MSGL_V,
"No event format found, using fallback");
Modified: trunk/libass/ass.h
==============================================================================
--- trunk/libass/ass.h Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass.h Tue Sep 24 22:50:02 2013 (r36459)
@@ -23,7 +23,7 @@
#include <stdarg.h>
#include "ass_types.h"
-#define LIBASS_VERSION 0x01010000
+#define LIBASS_VERSION 0x01020000
/*
* A linked list of images produced by an ass renderer.
@@ -44,6 +44,13 @@ typedef struct ass_image {
int dst_x, dst_y; // Bitmap placement inside the video frame
struct ass_image *next; // Next image, or NULL
+
+ enum {
+ IMAGE_TYPE_CHARACTER,
+ IMAGE_TYPE_OUTLINE,
+ IMAGE_TYPE_SHADOW
+ } type;
+
} ASS_Image;
/*
@@ -153,6 +160,12 @@ void ass_renderer_done(ASS_Renderer *pri
/**
* \brief Set the frame size in pixels, including margins.
+ * The renderer will never return images that are outside of the frame area.
+ * The value set with this function can influence the pixel aspect ratio used
+ * for rendering. If the frame size doesn't equal to the video size, you may
+ * have to use ass_set_pixel_aspect().
+ * @see ass_set_pixel_aspect()
+ * @see ass_set_margins()
* \param priv renderer handle
* \param w width
* \param h height
@@ -160,6 +173,19 @@ void ass_renderer_done(ASS_Renderer *pri
void ass_set_frame_size(ASS_Renderer *priv, int w, int h);
/**
+ * \brief Set the source image size in pixels.
+ * This is used to calculate the source aspect ratio and the blur scale.
+ * The source image size can be reset to default by setting w and h to 0.
+ * The value set with this function can influence the pixel aspect ratio used
+ * for rendering.
+ * @see ass_set_pixel_aspect()
+ * \param priv renderer handle
+ * \param w width
+ * \param h height
+ */
+void ass_set_storage_size(ASS_Renderer *priv, int w, int h);
+
+/**
* \brief Set shaping level. This is merely a hint, the renderer will use
* whatever is available if the request cannot be fulfilled.
* \param level shaping level
@@ -168,7 +194,26 @@ void ass_set_shaper(ASS_Renderer *priv,
/**
* \brief Set frame margins. These values may be negative if pan-and-scan
- * is used.
+ * is used. The margins are in pixels. Each value specifies the distance from
+ * the video rectangle to the renderer frame. If a given margin value is
+ * positive, there will be free space between renderer frame and video area.
+ * If a given margin value is negative, the frame is inside the video, i.e.
+ * the video has been cropped.
+ *
+ * The renderer will try to keep subtitles inside the frame area. If possible,
+ * text is layout so that it is inside the cropped area. Subtitle events
+ * that can't be moved are cropped against the frame area.
+ *
+ * ass_set_use_margins() can be used to allow libass to render subtitles into
+ * the empty areas if margins are positive, i.e. the video area is smaller than
+ * the frame. (Traditionally, this has been used to show subtitles in
+ * the bottom "black bar" between video bottom screen border when playing 16:9
+ * video on a 4:3 screen.)
+ *
+ * When using this function, it is recommended to calculate and set your own
+ * aspect ratio with ass_set_pixel_aspect(), as the defaults won't make any
+ * sense.
+ * @see ass_set_pixel_aspect()
* \param priv renderer handle
* \param t top margin
* \param b bottom margin
@@ -185,7 +230,29 @@ void ass_set_margins(ASS_Renderer *priv,
void ass_set_use_margins(ASS_Renderer *priv, int use);
/**
+ * \brief Set pixel aspect ratio correction.
+ * This is the ratio of pixel width to pixel height.
+ *
+ * Generally, this is (s_w / s_h) / (d_w / d_h), where s_w and s_h is the
+ * video storage size, and d_w and d_h is the video display size. (Display
+ * and storage size can be different for anamorphic video, such as DVDs.)
+ *
+ * If the pixel aspect ratio is 0, or if the aspect ratio has never been set
+ * by calling this function, libass will calculate a default pixel aspect ratio
+ * out of values set with ass_set_frame_size() and ass_set_storage_size(). Note
+ * that this is useful only if the frame size corresponds to the video display
+ * size. Keep in mind that the margins set with ass_set_margins() are ignored
+ * for aspect ratio calculations as well.
+ * If the storage size has not been set, a pixel aspect ratio of 1 is assumed.
+ * \param priv renderer handle
+ * \param par pixel aspect ratio (1.0 means square pixels, 0 means default)
+ */
+void ass_set_pixel_aspect(ASS_Renderer *priv, double par);
+
+/**
* \brief Set aspect ratio parameters.
+ * This calls ass_set_pixel_aspect(priv, dar / sar).
+ * @deprecated New code should use ass_set_pixel_aspect().
* \param priv renderer handle
* \param dar display aspect ratio (DAR), prescaled for output PAR
* \param sar storage aspect ratio (SAR)
Modified: trunk/libass/ass_bitmap.c
==============================================================================
--- trunk/libass/ass_bitmap.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_bitmap.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -456,7 +456,7 @@ int outline_to_bitmap3(ASS_Library *libr
FT_Library ftlib, FT_Outline *outline, FT_Outline *border,
Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
int be, double blur_radius, FT_Vector shadow_offset,
- int border_style)
+ int border_style, int border_visible)
{
blur_radius *= 2;
int bbord = be > 0 ? sqrt(2 * be) : 0;
@@ -485,7 +485,7 @@ int outline_to_bitmap3(ASS_Library *libr
while (be--) {
if (*bm_o)
be_blur(*bm_o);
- else
+ if (!*bm_o || border_style == 3)
be_blur(*bm_g);
}
@@ -493,7 +493,7 @@ int outline_to_bitmap3(ASS_Library *libr
if (blur_radius > 0.0) {
if (*bm_o)
resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h);
- else
+ if (!*bm_o || border_style == 3)
resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h);
generate_tables(priv_blur, blur_radius);
if (*bm_o)
@@ -501,7 +501,7 @@ int outline_to_bitmap3(ASS_Library *libr
(*bm_o)->w, (*bm_o)->h, (*bm_o)->stride,
(int *) priv_blur->gt2, priv_blur->g_r,
priv_blur->g_w);
- else
+ if (!*bm_o || border_style == 3)
ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp,
(*bm_g)->w, (*bm_g)->h, (*bm_g)->stride,
(int *) priv_blur->gt2, priv_blur->g_r,
@@ -512,8 +512,11 @@ int outline_to_bitmap3(ASS_Library *libr
if (*bm_o && border_style != 3) {
*bm_s = copy_bitmap(*bm_o);
fix_outline(*bm_g, *bm_o);
- } else if (*bm_o) {
+ } else if (*bm_o && border_visible) {
*bm_s = copy_bitmap(*bm_o);
+ } else if (*bm_o) {
+ *bm_s = *bm_o;
+ *bm_o = 0;
} else
*bm_s = copy_bitmap(*bm_g);
Modified: trunk/libass/ass_bitmap.h
==============================================================================
--- trunk/libass/ass_bitmap.h Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_bitmap.h Tue Sep 24 22:50:02 2013 (r36459)
@@ -46,12 +46,13 @@ Bitmap *outline_to_bitmap(ASS_Library *l
* \param bm_o out: pointer to the bitmap of outline (border) glyph 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 border_visible whether border is visible if border_style is 3
*/
int outline_to_bitmap3(ASS_Library *library, ASS_SynthPriv *priv_blur,
FT_Library ftlib, FT_Outline *outline, FT_Outline *border,
Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
int be, double blur_radius, FT_Vector shadow_offset,
- int border_style);
+ int border_style, int border_visible);
void ass_free_bitmap(Bitmap *bm);
Modified: trunk/libass/ass_font.c
==============================================================================
--- trunk/libass/ass_font.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_font.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -711,12 +711,12 @@ void fix_freetype_stroker(FT_Outline *ou
/* "inside" contour but we can't find anything it could be
* inside of - assume the font is buggy and it should be
* an "outside" contour, and reverse it */
- for (j = 0; j < (end + 1 - start) / 2; j++) {
- FT_Vector temp = outline->points[start + j];
- char temp2 = outline->tags[start + j];
- outline->points[start + j] = outline->points[end - j];
+ for (j = 0; j < (end - start) / 2; j++) {
+ FT_Vector temp = outline->points[start + 1 + j];
+ char temp2 = outline->tags[start + 1 + j];
+ outline->points[start + 1 + j] = outline->points[end - j];
outline->points[end - j] = temp;
- outline->tags[start + j] = outline->tags[end - j];
+ outline->tags[start + 1 + j] = outline->tags[end - j];
outline->tags[end - j] = temp2;
}
dir ^= 1;
Modified: trunk/libass/ass_fontconfig.c
==============================================================================
--- trunk/libass/ass_fontconfig.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_fontconfig.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -179,6 +179,14 @@ static char *select_font(ASS_Library *li
rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
if (!rc)
goto error;
+ /* Fontconfig defaults include a language setting, which it sets based on
+ * some environment variables or defaults to "en". Unset this as we don't
+ * know the real language, and because some some attached fonts lack
+ * non-ascii characters included in fontconfig's list of characters
+ * required for English support and therefore don't match the lang=en
+ * criterion.
+ */
+ FcPatternDel(pat, "lang");
fsorted = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
ffullname = match_fullname(library, priv, family, bold, italic);
Modified: trunk/libass/ass_parse.c
==============================================================================
--- trunk/libass/ass_parse.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_parse.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -311,7 +311,7 @@ char *parse_tag(ASS_Renderer *render_pri
int x0, y0, x1, y1;
int res = 1;
char *start = p;
- skipopt('(');
+ skip('(');
res &= mystrtoi(&p, &x0);
skipopt(',');
res &= mystrtoi(&p, &y0);
@@ -418,6 +418,7 @@ char *parse_tag(ASS_Renderer *render_pri
mystrtod(&p, &x2);
skip(',');
mystrtod(&p, &y2);
+ t1 = t2 = 0;
if (*p == ',') {
skip(',');
mystrtoll(&p, &t1);
@@ -427,13 +428,20 @@ char *parse_tag(ASS_Renderer *render_pri
"movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %"
PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1,
(int64_t) t2);
- } else {
+ // VSFilter
+ if (t1 > t2) {
+ double tmp = t2;
+ t2 = t1;
+ t1 = tmp;
+ }
+ }
+ if (t1 <= 0 && t2 <= 0) {
t1 = 0;
t2 = render_priv->state.event->Duration;
ass_msg(render_priv->library, MSGL_DBG2,
"movement: (%f, %f) -> (%f, %f)", x1, y1, x2, y2);
}
- skip(')');
+ skipopt(')');
delta_t = t2 - t1;
t = render_priv->time - render_priv->state.event->Start;
if (t < t1)
@@ -542,7 +550,7 @@ char *parse_tag(ASS_Renderer *render_pri
mystrtod(&p, &v1);
skip(',');
mystrtod(&p, &v2);
- skip(')');
+ skipopt(')');
ass_msg(render_priv->library, MSGL_DBG2, "pos(%f, %f)", v1, v2);
if (render_priv->state.evt_type == EVENT_POSITIONED) {
ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos "
@@ -586,7 +594,7 @@ char *parse_tag(ASS_Renderer *render_pri
skip(',');
mystrtoll(&p, &t4);
}
- skip(')');
+ skipopt(')');
if ((render_priv->state.parsed_tags & PARSED_FADE) == 0) {
render_priv->state.fade =
interpolate_alpha(render_priv->time -
@@ -600,7 +608,7 @@ char *parse_tag(ASS_Renderer *render_pri
mystrtoi(&p, &v1);
skip(',');
mystrtoi(&p, &v2);
- skip(')');
+ skipopt(')');
ass_msg(render_priv->library, MSGL_DBG2, "org(%d, %d)", v1, v2);
if (!render_priv->state.have_origin) {
render_priv->state.org_x = v1;
@@ -617,9 +625,8 @@ char *parse_tag(ASS_Renderer *render_pri
double k;
skip('(');
for (cnt = 0; cnt < 3; ++cnt) {
- if (*p == '\\')
+ if (!mystrtod(&p, &v[cnt]))
break;
- mystrtod(&p, &v[cnt]);
skip(',');
}
if (cnt == 3) {
@@ -654,15 +661,15 @@ char *parse_tag(ASS_Renderer *render_pri
assert(delta_t != 0.);
k = pow(((double) (t - t1)) / delta_t, v3);
}
- while (*p == '\\')
+ while (*p != ')' && *p != '}' && *p != '\0')
p = parse_tag(render_priv, p, k); // maybe k*pwr ? no, specs forbid nested \t's
skip_to(')'); // in case there is some unknown tag or a comment
- skip(')');
+ skipopt(')');
} else if (mystrcmp(&p, "clip")) {
char *start = p;
int x0, y0, x1, y1;
int res = 1;
- skipopt('(');
+ skip('(');
res &= mystrtoi(&p, &x0);
skipopt(',');
res &= mystrtoi(&p, &y0);
Modified: trunk/libass/ass_render.c
==============================================================================
--- trunk/libass/ass_render.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_render.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -240,7 +240,7 @@ static double y2scr_sub(ASS_Renderer *re
static ASS_Image **render_glyph_i(ASS_Renderer *render_priv,
Bitmap *bm, int dst_x, int dst_y,
uint32_t color, uint32_t color2, int brk,
- ASS_Image **tail)
+ ASS_Image **tail, unsigned int type)
{
int i, j, x0, y0, x1, y1, cx0, cy0, cx1, cy1, sx, sy, zx, zy;
Rect r[4];
@@ -308,6 +308,7 @@ static ASS_Image **render_glyph_i(ASS_Re
lbrk - r[j].x0, r[j].y1 - r[j].y0,
bm->stride, dst_x + r[j].x0, dst_y + r[j].y0, color);
if (!img) break;
+ img->type = type;
*tail = img;
tail = &img->next;
}
@@ -317,6 +318,7 @@ static ASS_Image **render_glyph_i(ASS_Re
r[j].x1 - lbrk, r[j].y1 - r[j].y0,
bm->stride, dst_x + lbrk, dst_y + r[j].y0, color2);
if (!img) break;
+ img->type = type;
*tail = img;
tail = &img->next;
}
@@ -339,12 +341,12 @@ static ASS_Image **render_glyph_i(ASS_Re
*/
static ASS_Image **
render_glyph(ASS_Renderer *render_priv, Bitmap *bm, int dst_x, int dst_y,
- uint32_t color, uint32_t color2, int brk, ASS_Image **tail)
+ uint32_t color, uint32_t color2, int brk, ASS_Image **tail, unsigned int type)
{
// Inverse clipping in use?
if (render_priv->state.clip_mode)
return render_glyph_i(render_priv, bm, dst_x, dst_y, color, color2,
- brk, tail);
+ brk, tail, type);
// brk is relative to dst_x
// color = color left of brk
@@ -399,6 +401,7 @@ render_glyph(ASS_Renderer *render_priv,
brk - b_x0, b_y1 - b_y0, bm->stride,
dst_x + b_x0, dst_y + b_y0, color);
if (!img) return tail;
+ img->type = type;
*tail = img;
tail = &img->next;
}
@@ -409,6 +412,7 @@ render_glyph(ASS_Renderer *render_priv,
b_x1 - brk, b_y1 - b_y0, bm->stride,
dst_x + brk, dst_y + b_y0, color2);
if (!img) return tail;
+ img->type = type;
*tail = img;
tail = &img->next;
}
@@ -718,7 +722,7 @@ static ASS_Image *render_text(ASS_Render
here_tail = tail;
tail =
render_glyph(render_priv, bm, pen_x, pen_y, info->c[3], 0,
- 1000000, tail);
+ 1000000, tail, IMAGE_TYPE_SHADOW);
if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0))
render_overlap(render_priv, last_tail, here_tail);
@@ -752,7 +756,7 @@ static ASS_Image *render_text(ASS_Render
here_tail = tail;
tail =
render_glyph(render_priv, bm, pen_x, pen_y, info->c[2],
- 0, 1000000, tail);
+ 0, 1000000, tail, IMAGE_TYPE_OUTLINE);
if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0))
render_overlap(render_priv, last_tail, here_tail);
@@ -783,19 +787,19 @@ static ASS_Image *render_text(ASS_Render
if (info->effect_timing > (info->bbox.xMax >> 6))
tail =
render_glyph(render_priv, bm, pen_x, pen_y,
- info->c[0], 0, 1000000, tail);
+ info->c[0], 0, 1000000, tail, IMAGE_TYPE_CHARACTER);
else
tail =
render_glyph(render_priv, bm, pen_x, pen_y,
- info->c[1], 0, 1000000, tail);
+ info->c[1], 0, 1000000, tail, IMAGE_TYPE_CHARACTER);
} else if (info->effect_type == EF_KARAOKE_KF) {
tail =
render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
- info->c[1], info->effect_timing, tail);
+ info->c[1], info->effect_timing, tail, IMAGE_TYPE_CHARACTER);
} else
tail =
render_glyph(render_priv, bm, pen_x, pen_y, info->c[0],
- 0, 1000000, tail);
+ 0, 1000000, tail, IMAGE_TYPE_CHARACTER);
info = info->next;
}
}
@@ -866,7 +870,7 @@ void reset_render_context(ASS_Renderer *
render_priv->state.scale_y = style->ScaleY;
render_priv->state.hspacing = style->Spacing;
render_priv->state.be = 0;
- render_priv->state.blur = 0.0;
+ render_priv->state.blur = style->Blur;
render_priv->state.shadow_x = style->Shadow;
render_priv->state.shadow_y = style->Shadow;
render_priv->state.frx = render_priv->state.fry = 0.;
@@ -927,13 +931,14 @@ static void free_render_context(ASS_Rend
* Replace the outline of a glyph by a contour which makes up a simple
* opaque rectangle.
*/
-static void draw_opaque_box(ASS_Renderer *render_priv, int asc, int desc,
- FT_Outline *ol, FT_Vector advance, int sx, int sy)
+static void draw_opaque_box(ASS_Renderer *render_priv, GlyphInfo *info,
+ int asc, int desc, FT_Outline *ol,
+ FT_Vector advance, int sx, int sy)
{
int i;
int adv = advance.x;
- double scale_y = render_priv->state.scale_y;
- double scale_x = render_priv->state.scale_x;
+ double scale_y = info->scale_y;
+ double scale_x = info->scale_x;
// to avoid gaps
sx = FFMAX(64, sx);
@@ -941,8 +946,7 @@ static void draw_opaque_box(ASS_Renderer
// Emulate the WTFish behavior of VSFilter, i.e. double-scale
// the sizes of the opaque box.
- adv += double_to_d6(render_priv->state.hspacing * render_priv->font_scale
- * scale_x);
+ adv += double_to_d6(info->hspacing * render_priv->font_scale * scale_x);
adv *= scale_x;
sx *= scale_x;
sy *= scale_y;
@@ -1127,8 +1131,7 @@ get_outline_glyph(ASS_Renderer *priv, Gl
FT_Outline_Get_CBox(v.outline, &v.bbox_scaled);
- if (info->border_style == 3 &&
- (info->border_x > 0 || info->border_y > 0)) {
+ if (info->border_style == 3) {
FT_Vector advance;
v.border = calloc(1, sizeof(FT_Outline));
@@ -1138,7 +1141,7 @@ get_outline_glyph(ASS_Renderer *priv, Gl
else
advance = info->advance;
- draw_opaque_box(priv, v.asc, v.desc, v.border, advance,
+ draw_opaque_box(priv, info, v.asc, v.desc, v.border, advance,
double_to_d6(info->border_x * priv->border_scale),
double_to_d6(info->border_y * priv->border_scale));
@@ -1311,9 +1314,10 @@ get_bitmap_glyph(ASS_Renderer *render_pr
outline, border,
&hash_val.bm, &hash_val.bm_o,
&hash_val.bm_s, info->be,
- info->blur * render_priv->border_scale,
+ info->blur * render_priv->blur_scale,
key->shadow_offset,
- info->border_style);
+ info->border_style,
+ info->border_x || info->border_y);
if (error)
info->symbol = 0;
@@ -2244,21 +2248,37 @@ ass_start_frame(ASS_Renderer *render_pri
render_priv->font_scale = settings_priv->font_size_coeff *
render_priv->orig_height / render_priv->track->PlayResY;
+ if (render_priv->storage_height)
+ render_priv->blur_scale = ((double) render_priv->orig_height) /
+ render_priv->storage_height;
+ else
+ render_priv->blur_scale = 1.;
if (render_priv->track->ScaledBorderAndShadow)
render_priv->border_scale =
((double) render_priv->orig_height) /
render_priv->track->PlayResY;
else
- render_priv->border_scale = 1.;
+ render_priv->border_scale = render_priv->blur_scale;
+ render_priv->border_scale *= settings_priv->font_size_coeff;
ass_shaper_set_kerning(render_priv->shaper, track->Kerning);
- if (track->Language)
- ass_shaper_set_language(render_priv->shaper, track->Language);
+ ass_shaper_set_language(render_priv->shaper, track->Language);
ass_shaper_set_level(render_priv->shaper, render_priv->settings.shaper);
// PAR correction
- render_priv->font_scale_x = render_priv->settings.aspect /
- render_priv->settings.storage_aspect;
+ double par = render_priv->settings.par;
+ if (par == 0.) {
+ if (settings_priv->frame_width && settings_priv->frame_height &&
+ settings_priv->storage_width && settings_priv->storage_height) {
+ double dar = ((double) settings_priv->frame_width) /
+ settings_priv->frame_height;
+ double sar = ((double) settings_priv->storage_width) /
+ settings_priv->storage_height;
+ par = sar / dar;
+ } else
+ par = 1.0;
+ }
+ render_priv->font_scale_x = par;
render_priv->prev_images_root = render_priv->images_root;
render_priv->images_root = 0;
Modified: trunk/libass/ass_render.h
==============================================================================
--- trunk/libass/ass_render.h Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_render.h Tue Sep 24 22:50:02 2013 (r36459)
@@ -26,6 +26,9 @@
#include FT_STROKER_H
#include FT_GLYPH_H
#include FT_SYNTHESIS_H
+#ifdef CONFIG_HARFBUZZ
+#include "hb.h"
+#endif
// XXX: fix the inclusion mess so we can avoid doing this here
typedef struct ass_shaper ASS_Shaper;
@@ -65,6 +68,8 @@ typedef struct free_list {
typedef struct {
int frame_width;
int frame_height;
+ int storage_width; // width of the source image
+ int storage_height; // height of the source image
double font_size_coeff; // font size multiplier
double line_spacing; // additional line spacing (in frame pixels)
double line_position; // vertical position for subtitles, 0-100 (0 = no change)
@@ -74,8 +79,7 @@ typedef struct {
int right_margin;
int use_margins; // 0 - place all subtitles inside original frame
// 1 - use margins for placing toptitles and subtitles
- double aspect; // frame aspect ratio, d_width / d_height.
- double storage_aspect; // pixel ratio of the source image
+ double par; // user defined pixel aspect ratio (0 = unset)
ASS_Hinting hinting;
ASS_ShapingLevel shaper;
@@ -107,6 +111,11 @@ typedef struct glyph_info {
ASS_Font *font;
int face_index;
int glyph_index;
+#ifdef CONFIG_HARFBUZZ
+ hb_script_t script;
+#else
+ int script;
+#endif
double font_size;
ASS_Drawing *drawing;
FT_Outline *outline;
@@ -264,11 +273,14 @@ struct ass_renderer {
int orig_width; // frame width ( = screen width - margins )
int orig_height_nocrop; // frame height ( = screen height - margins + cropheight)
int orig_width_nocrop; // frame width ( = screen width - margins + cropwidth)
+ int storage_height; // video height before any rescaling
+ int storage_width; // video width before any rescaling
ASS_Track *track;
long long time; // frame's timestamp, ms
double font_scale;
double font_scale_x; // x scale applied to all glyphs to preserve text aspect ratio
double border_scale;
+ double blur_scale;
RenderContext state;
TextInfo text_info;
Modified: trunk/libass/ass_render_api.c
==============================================================================
--- trunk/libass/ass_render_api.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_render_api.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -43,6 +43,13 @@ static void ass_reconfigure(ASS_Renderer
priv->orig_height_nocrop =
settings->frame_height - FFMAX(settings->top_margin, 0) -
FFMAX(settings->bottom_margin, 0);
+ if (settings->storage_height) {
+ priv->storage_width = settings->storage_width;
+ priv->storage_height = settings->storage_height;
+ } else {
+ priv->storage_width = priv->orig_width;
+ priv->storage_height = priv->orig_height;
+ }
}
void ass_set_frame_size(ASS_Renderer *priv, int w, int h)
@@ -50,10 +57,16 @@ void ass_set_frame_size(ASS_Renderer *pr
if (priv->settings.frame_width != w || priv->settings.frame_height != h) {
priv->settings.frame_width = w;
priv->settings.frame_height = h;
- if (priv->settings.aspect == 0.) {
- priv->settings.aspect = ((double) w) / h;
- priv->settings.storage_aspect = ((double) w) / h;
- }
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_storage_size(ASS_Renderer *priv, int w, int h)
+{
+ if (priv->settings.storage_width != w ||
+ priv->settings.storage_height != h) {
+ priv->settings.storage_width = w;
+ priv->settings.storage_height = h;
ass_reconfigure(priv);
}
}
@@ -88,9 +101,13 @@ void ass_set_use_margins(ASS_Renderer *p
void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar)
{
- if (priv->settings.aspect != dar || priv->settings.storage_aspect != sar) {
- priv->settings.aspect = dar;
- priv->settings.storage_aspect = sar;
+ ass_set_pixel_aspect(priv, dar / sar);
+}
+
+void ass_set_pixel_aspect(ASS_Renderer *priv, double par)
+{
+ if (priv->settings.par != par) {
+ priv->settings.par = par;
ass_reconfigure(priv);
}
}
Modified: trunk/libass/ass_shaper.c
==============================================================================
--- trunk/libass/ass_shaper.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_shaper.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -213,6 +213,12 @@ get_cached_metrics(struct ass_shaper_met
return NULL;
memcpy(&new_val.metrics, &face->glyph->metrics, sizeof(FT_Glyph_Metrics));
+
+ // if @font rendering is enabled and the glyph should be rotated,
+ // make cached_h_advance pick up the right advance later
+ if (metrics->vertical && glyph >= VERTICAL_LOWER_BOUND)
+ new_val.metrics.horiAdvance = new_val.metrics.vertAdvance;
+
val = ass_cache_put(metrics->metrics_cache, &metrics->hash_key, &new_val);
}
@@ -244,9 +250,6 @@ cached_h_advance(hb_font_t *font, void *
if (!metrics)
return 0;
- if (metrics_priv->vertical && glyph > VERTICAL_LOWER_BOUND)
- return metrics->metrics.vertAdvance;
-
return metrics->metrics.horiAdvance;
}
@@ -419,6 +422,107 @@ static hb_font_t *get_hb_font(ASS_Shaper
}
/**
+ * \brief Map script to default language.
+ *
+ * This maps a script to a language, if a script has a representative
+ * language it is typically used with. Otherwise, the invalid language
+ * is returned.
+ *
+ * The mapping is similar to Pango's pango-language.c.
+ *
+ * \param script script tag
+ * \return language tag
+ */
+static hb_language_t script_to_language(hb_script_t script)
+{
+ switch (script) {
+ // Unicode 1.1
+ case HB_SCRIPT_ARABIC: return hb_language_from_string("ar", -1); break;
+ case HB_SCRIPT_ARMENIAN: return hb_language_from_string("hy", -1); break;
+ case HB_SCRIPT_BENGALI: return hb_language_from_string("bn", -1); break;
+ case HB_SCRIPT_CANADIAN_ABORIGINAL: return hb_language_from_string("iu", -1); break;
+ case HB_SCRIPT_CHEROKEE: return hb_language_from_string("chr", -1); break;
+ case HB_SCRIPT_COPTIC: return hb_language_from_string("cop", -1); break;
+ case HB_SCRIPT_CYRILLIC: return hb_language_from_string("ru", -1); break;
+ case HB_SCRIPT_DEVANAGARI: return hb_language_from_string("hi", -1); break;
+ case HB_SCRIPT_GEORGIAN: return hb_language_from_string("ka", -1); break;
+ case HB_SCRIPT_GREEK: return hb_language_from_string("el", -1); break;
+ case HB_SCRIPT_GUJARATI: return hb_language_from_string("gu", -1); break;
+ case HB_SCRIPT_GURMUKHI: return hb_language_from_string("pa", -1); break;
+ case HB_SCRIPT_HANGUL: return hb_language_from_string("ko", -1); break;
+ case HB_SCRIPT_HEBREW: return hb_language_from_string("he", -1); break;
+ case HB_SCRIPT_HIRAGANA: return hb_language_from_string("ja", -1); break;
+ case HB_SCRIPT_KANNADA: return hb_language_from_string("kn", -1); break;
+ case HB_SCRIPT_KATAKANA: return hb_language_from_string("ja", -1); break;
+ case HB_SCRIPT_LAO: return hb_language_from_string("lo", -1); break;
+ case HB_SCRIPT_LATIN: return hb_language_from_string("en", -1); break;
+ case HB_SCRIPT_MALAYALAM: return hb_language_from_string("ml", -1); break;
+ case HB_SCRIPT_MONGOLIAN: return hb_language_from_string("mn", -1); break;
+ case HB_SCRIPT_ORIYA: return hb_language_from_string("or", -1); break;
+ case HB_SCRIPT_SYRIAC: return hb_language_from_string("syr", -1); break;
+ case HB_SCRIPT_TAMIL: return hb_language_from_string("ta", -1); break;
+ case HB_SCRIPT_TELUGU: return hb_language_from_string("te", -1); break;
+ case HB_SCRIPT_THAI: return hb_language_from_string("th", -1); break;
+
+ // Unicode 2.0
+ case HB_SCRIPT_TIBETAN: return hb_language_from_string("bo", -1); break;
+
+ // Unicode 3.0
+ case HB_SCRIPT_ETHIOPIC: return hb_language_from_string("am", -1); break;
+ case HB_SCRIPT_KHMER: return hb_language_from_string("km", -1); break;
+ case HB_SCRIPT_MYANMAR: return hb_language_from_string("my", -1); break;
+ case HB_SCRIPT_SINHALA: return hb_language_from_string("si", -1); break;
+ case HB_SCRIPT_THAANA: return hb_language_from_string("dv", -1); break;
+
+ // Unicode 3.2
+ case HB_SCRIPT_BUHID: return hb_language_from_string("bku", -1); break;
+ case HB_SCRIPT_HANUNOO: return hb_language_from_string("hnn", -1); break;
+ case HB_SCRIPT_TAGALOG: return hb_language_from_string("tl", -1); break;
+ case HB_SCRIPT_TAGBANWA: return hb_language_from_string("tbw", -1); break;
+
+ // Unicode 4.0
+ case HB_SCRIPT_UGARITIC: return hb_language_from_string("uga", -1); break;
+
+ // Unicode 4.1
+ case HB_SCRIPT_BUGINESE: return hb_language_from_string("bug", -1); break;
+ case HB_SCRIPT_OLD_PERSIAN: return hb_language_from_string("peo", -1); break;
+ case HB_SCRIPT_SYLOTI_NAGRI: return hb_language_from_string("syl", -1); break;
+
+ // Unicode 5.0
+ case HB_SCRIPT_NKO: return hb_language_from_string("nko", -1); break;
+
+ // no representative language exists
+ default: return HB_LANGUAGE_INVALID; break;
+ }
+}
+
+/**
+ * \brief Determine language to be used for shaping a run.
+ *
+ * \param shaper shaper instance
+ * \param script script tag associated with run
+ * \return language tag
+ */
+static hb_language_t
+hb_shaper_get_run_language(ASS_Shaper *shaper, hb_script_t script)
+{
+ hb_language_t lang;
+
+ // override set, use it
+ if (shaper->language != HB_LANGUAGE_INVALID)
+ return shaper->language;
+
+ // get default language for given script
+ lang = script_to_language(script);
+
+ // no dice, use system default
+ if (lang == HB_LANGUAGE_INVALID)
+ lang = hb_language_get_default();
+
+ return lang;
+}
+
+/**
* \brief Shape event text with HarfBuzz. Full OpenType shaping.
* \param glyphs glyph clusters
* \param len number of clusters
@@ -440,6 +544,7 @@ static void shape_harfbuzz(ASS_Shaper *s
int k = i;
int level = glyphs[i].shape_run_id;
int direction = shaper->emblevels[k] % 2;
+ hb_script_t script = glyphs[i].script;
while (i < (len - 1) && level == glyphs[i+1].shape_run_id)
i++;
runs[run].offset = k;
@@ -450,7 +555,9 @@ static void shape_harfbuzz(ASS_Shaper *s
hb_buffer_pre_allocate(runs[run].buf, i - k + 1);
hb_buffer_set_direction(runs[run].buf, direction ? HB_DIRECTION_RTL :
HB_DIRECTION_LTR);
- hb_buffer_set_language(runs[run].buf, shaper->language);
+ hb_buffer_set_language(runs[run].buf,
+ hb_shaper_get_run_language(shaper, script));
+ hb_buffer_set_script(runs[run].buf, script);
hb_buffer_add_utf32(runs[run].buf, shaper->event_text + k, i - k + 1,
0, i - k + 1);
hb_shape(runs[run].font, runs[run].buf, shaper->features,
@@ -503,6 +610,56 @@ static void shape_harfbuzz(ASS_Shaper *s
}
}
+
+/**
+ * \brief Determine script property of all characters. Characters of script
+ * common and inherited get their script from their context.
+ *
+ */
+void ass_shaper_determine_script(ASS_Shaper *shaper, GlyphInfo *glyphs,
+ size_t len)
+{
+ int i;
+ int backwards_scan = 0;
+ hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default();
+ hb_script_t last_script = HB_SCRIPT_UNKNOWN;
+
+ // determine script (forward scan)
+ for (i = 0; i < len; i++) {
+ GlyphInfo *info = glyphs + i;
+ info->script = hb_unicode_script(ufuncs, info->symbol);
+
+ // common/inherit codepoints inherit script from context
+ if (info->script == HB_SCRIPT_COMMON ||
+ info->script == HB_SCRIPT_INHERITED) {
+ // unknown is not a valid context
+ if (last_script != HB_SCRIPT_UNKNOWN)
+ info->script = last_script;
+ else
+ // do a backwards scan to check if next codepoint
+ // contains a valid script for context
+ backwards_scan = 1;
+ } else {
+ last_script = info->script;
+ }
+ }
+
+ // determine script (backwards scan, if needed)
+ last_script = HB_SCRIPT_UNKNOWN;
+ for (i = len - 1; i >= 0 && backwards_scan; i--) {
+ GlyphInfo *info = glyphs + i;
+
+ // common/inherit codepoints inherit script from context
+ if (info->script == HB_SCRIPT_COMMON ||
+ info->script == HB_SCRIPT_INHERITED) {
+ // unknown script is not a valid context
+ if (last_script != HB_SCRIPT_UNKNOWN)
+ info->script = last_script;
+ } else {
+ last_script = info->script;
+ }
+ }
+}
#endif
#ifdef CONFIG_FRIBIDI
@@ -555,6 +712,11 @@ void ass_shaper_find_runs(ASS_Shaper *sh
int i;
int shape_run = 0;
+#ifdef CONFIG_HARFBUZZ
+ ass_shaper_determine_script(shaper, glyphs, len);
+#endif
+
+ // find appropriate fonts for the shape runs
for (i = 0; i < len; i++) {
GlyphInfo *last = glyphs + i - 1;
GlyphInfo *info = glyphs + i;
@@ -567,11 +729,11 @@ void ass_shaper_find_runs(ASS_Shaper *sh
// shape runs share the same font face and size
if (i > 0 && (last->font != info->font ||
last->font_size != info->font_size ||
- last->face_index != info->face_index))
+ last->face_index != info->face_index ||
+ last->script != info->script))
shape_run++;
info->shape_run_id = shape_run;
}
-
}
/**
@@ -591,7 +753,14 @@ void ass_shaper_set_base_direction(ASS_S
void ass_shaper_set_language(ASS_Shaper *shaper, const char *code)
{
#ifdef CONFIG_HARFBUZZ
- shaper->language = hb_language_from_string(code, -1);
+ hb_language_t lang;
+
+ if (code)
+ lang = hb_language_from_string(code, -1);
+ else
+ lang = HB_LANGUAGE_INVALID;
+
+ shaper->language = lang;
#endif
}
Modified: trunk/libass/ass_types.h
==============================================================================
--- trunk/libass/ass_types.h Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_types.h Tue Sep 24 22:50:02 2013 (r36459)
@@ -50,7 +50,7 @@ typedef struct ass_style {
double ScaleX;
double ScaleY;
double Spacing;
- int Angle;
+ double Angle;
int BorderStyle;
double Outline;
double Shadow;
@@ -60,6 +60,7 @@ typedef struct ass_style {
int MarginV;
int Encoding;
int treat_fontname_as_pattern;
+ double Blur;
} ASS_Style;
/*
@@ -113,6 +114,19 @@ typedef struct ass_track {
int ScaledBorderAndShadow;
int Kerning;
char *Language;
+ enum {
+ YCBCR_DEFAULT = 0, // TV.601 on YCbCr video, None on RGB video
+ YCBCR_UNKNOWN,
+ YCBCR_NONE, // untouched RGB values
+ YCBCR_BT601_TV,
+ YCBCR_BT601_PC,
+ YCBCR_BT709_TV,
+ YCBCR_BT709_PC,
+ YCBCR_SMPTE240M_TV,
+ YCBCR_SMPTE240M_PC,
+ YCBCR_FCC_TV,
+ YCBCR_FCC_PC
+ } YCbCrMatrix;
int default_style; // index of default style
char *name; // file name in case of external subs, 0 for streams
Modified: trunk/libass/ass_utils.c
==============================================================================
--- trunk/libass/ass_utils.c Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_utils.c Tue Sep 24 22:50:02 2013 (r36459)
@@ -122,6 +122,46 @@ char parse_bool(char *str)
return 0;
}
+int parse_ycbcr_matrix(char *str)
+{
+ while (*str == ' ' || *str == '\t')
+ str++;
+ if (*str == '\0')
+ return YCBCR_DEFAULT;
+
+ char *end = str + strlen(str);
+ while (end[-1] == ' ' || end[-1] == '\t')
+ end--;
+
+ // Trim a local copy of the input that we know is safe to
+ // modify. The buffer is larger than any valid string + NUL,
+ // so we can simply chop off the rest of the input.
+ char buffer[16];
+ size_t n = FFMIN(end - str, sizeof buffer - 1);
+ strncpy(buffer, str, n);
+ buffer[n] = '\0';
+
+ if (!strcasecmp(buffer, "none"))
+ return YCBCR_NONE;
+ if (!strcasecmp(buffer, "tv.601"))
+ return YCBCR_BT601_TV;
+ if (!strcasecmp(buffer, "pc.601"))
+ return YCBCR_BT601_PC;
+ if (!strcasecmp(buffer, "tv.709"))
+ return YCBCR_BT709_TV;
+ if (!strcasecmp(buffer, "pc.709"))
+ return YCBCR_BT709_PC;
+ if (!strcasecmp(buffer, "tv.240m"))
+ return YCBCR_SMPTE240M_TV;
+ if (!strcasecmp(buffer, "pc.240m"))
+ return YCBCR_SMPTE240M_PC;
+ if (!strcasecmp(buffer, "tv.fcc"))
+ return YCBCR_FCC_TV;
+ if (!strcasecmp(buffer, "pc.fcc"))
+ return YCBCR_FCC_PC;
+ return YCBCR_UNKNOWN;
+}
+
void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...)
{
va_list va;
Modified: trunk/libass/ass_utils.h
==============================================================================
--- trunk/libass/ass_utils.h Sun Sep 22 11:03:30 2013 (r36458)
+++ trunk/libass/ass_utils.h Tue Sep 24 22:50:02 2013 (r36459)
@@ -49,6 +49,7 @@ int mystrtou32(char **p, int base, uint3
int mystrtod(char **p, double *res);
int strtocolor(ASS_Library *library, char **q, uint32_t *res, int hex);
char parse_bool(char *str);
+int parse_ycbcr_matrix(char *str);
unsigned ass_utf8_get_char(char **str);
void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...);
int lookup_style(ASS_Track *track, char *name);
More information about the MPlayer-cvslog
mailing list