ass_render.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 2,195 行 · 第 1/5 页
C
2,195 行
*tail = 0; return head;}/** * \brief Mapping between script and screen coordinates */static int x2scr(int x) { return x*frame_context.orig_width / frame_context.track->PlayResX + global_settings->left_margin;}/** * \brief Mapping between script and screen coordinates */static int y2scr(int y) { return y * frame_context.orig_height / frame_context.track->PlayResY + global_settings->top_margin;}// the same for toptitlesstatic int y2scr_top(int y) { if (global_settings->use_margins) return y * frame_context.orig_height / frame_context.track->PlayResY; else return y * frame_context.orig_height / frame_context.track->PlayResY + global_settings->top_margin;}// the same for subtitlesstatic int y2scr_sub(int y) { if (global_settings->use_margins) return y * frame_context.orig_height / frame_context.track->PlayResY + global_settings->top_margin + global_settings->bottom_margin; else return y * frame_context.orig_height / frame_context.track->PlayResY + global_settings->top_margin;}static void compute_string_bbox( text_info_t* info, FT_BBox *abbox ) { FT_BBox bbox; int i; if (text_info.length > 0) { bbox.xMin = 32000; bbox.xMax = -32000; bbox.yMin = - d6_to_int(text_info.lines[0].asc) + text_info.glyphs[0].pos.y; bbox.yMax = d6_to_int(text_info.height - text_info.lines[0].asc) + text_info.glyphs[0].pos.y; for (i = 0; i < text_info.length; ++i) { int s = text_info.glyphs[i].pos.x; int e = s + d6_to_int(text_info.glyphs[i].advance.x); bbox.xMin = FFMIN(bbox.xMin, s); bbox.xMax = FFMAX(bbox.xMax, e); } } else bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0; /* return string bbox */ *abbox = bbox;}/** * \brief Check if starting part of (*p) matches sample. If true, shift p to the first symbol after the matching part. */static inline int mystrcmp(char** p, const char* sample) { int len = strlen(sample); if (strncmp(*p, sample, len) == 0) { (*p) += len; return 1; } else return 0;}static void change_font_size(double sz){ double size = sz * frame_context.font_scale; if (size < 1) size = 1; else if (size > frame_context.height * 2) size = frame_context.height * 2; ass_font_set_size(render_context.font, size); render_context.font_size = sz;}/** * \brief Change current font, using setting from render_context. */static void update_font(void){ unsigned val; ass_renderer_t* priv = frame_context.ass_priv; ass_font_desc_t desc; desc.family = strdup(render_context.family); val = render_context.bold; // 0 = normal, 1 = bold, >1 = exact weight if (val == 0) val = 80; // normal else if (val == 1) val = 200; // bold desc.bold = val; val = render_context.italic; if (val == 0) val = 0; // normal else if (val == 1) val = 110; //italic desc.italic = val; render_context.font = ass_font_new(priv->library, priv->ftlibrary, priv->fontconfig_priv, &desc); free(desc.family); if (render_context.font) change_font_size(render_context.font_size);}/** * \brief Change border width * negative value resets border to style value */static void change_border(double border){ int b; if (!render_context.font) return; if (border < 0) { if (render_context.style->BorderStyle == 1) { if (render_context.style->Outline == 0 && render_context.style->Shadow > 0) border = 1.; else border = render_context.style->Outline; } else border = 1.; } render_context.border = border; b = 64 * border * frame_context.border_scale; if (b > 0) { if (!render_context.stroker) { int error;#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1)) error = FT_Stroker_New( ass_renderer->ftlibrary, &render_context.stroker );#else // < 2.2 error = FT_Stroker_New( render_context.font->faces[0]->memory, &render_context.stroker );#endif if (error) { mp_msg(MSGT_ASS, MSGL_V, "failed to get stroker\n"); render_context.stroker = 0; } } if (render_context.stroker) FT_Stroker_Set( render_context.stroker, b, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 ); } else { FT_Stroker_Done(render_context.stroker); render_context.stroker = 0; }}#define _r(c) ((c)>>24)#define _g(c) (((c)>>16)&0xFF)#define _b(c) (((c)>>8)&0xFF)#define _a(c) ((c)&0xFF)/** * \brief Calculate a weighted average of two colors * calculates c1*(1-a) + c2*a, but separately for each component except alpha */static void change_color(uint32_t* var, uint32_t new, double pwr){ (*var)= ((uint32_t)(_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) + ((uint32_t)(_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) + ((uint32_t)(_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) + _a(*var);}// like change_color, but for alpha component onlystatic void change_alpha(uint32_t* var, uint32_t new, double pwr){ *var = (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) + (_a(*var) * (1 - pwr) + _a(new) * pwr);}/** * \brief Multiply two alpha values * \param a first value * \param b second value * \return result of multiplication * Parameters and result are limited by 0xFF. */static uint32_t mult_alpha(uint32_t a, uint32_t b){ return 0xFF - (0xFF - a) * (0xFF - b) / 0xFF;}/** * \brief Calculate alpha value by piecewise linear function * Used for \fad, \fade implementation. */static unsigned interpolate_alpha(long long now, long long t1, long long t2, long long t3, long long t4, unsigned a1, unsigned a2, unsigned a3){ unsigned a; double cf; if (now <= t1) { a = a1; } else if (now >= t4) { a = a3; } else if (now < t2) { // and > t1 cf = ((double)(now - t1)) / (t2 - t1); a = a1 * (1 - cf) + a2 * cf; } else if (now > t3) { cf = ((double)(now - t3)) / (t4 - t3); a = a2 * (1 - cf) + a3 * cf; } else { // t2 <= now <= t3 a = a2; } return a;}static void reset_render_context(void);/** * \brief Parse style override tag. * \param p string to parse * \param pwr multiplier for some tag effects (comes from \t tags) */static char* parse_tag(char* p, double pwr) {#define skip_all(x) if (*p == (x)) ++p; else { \ while ((*p != (x)) && (*p != '}') && (*p != 0)) {++p;} }#define skip(x) if (*p == (x)) ++p; else { return p; } skip_all('\\'); if ((*p == '}') || (*p == 0)) return p; if (mystrcmp(&p, "fsc")) { char tp = *p++; double val; if (tp == 'x') { if (mystrtod(&p, &val)) { val /= 100; render_context.scale_x = render_context.scale_x * ( 1 - pwr) + val * pwr; } else render_context.scale_x = render_context.style->ScaleX; } else if (tp == 'y') { if (mystrtod(&p, &val)) { val /= 100; render_context.scale_y = render_context.scale_y * ( 1 - pwr) + val * pwr; } else render_context.scale_y = render_context.style->ScaleY; } } else if (mystrcmp(&p, "fsp")) { double val; if (mystrtod(&p, &val)) render_context.hspacing = render_context.hspacing * ( 1 - pwr ) + val * pwr; else render_context.hspacing = render_context.style->Spacing; } else if (mystrcmp(&p, "fs")) { double val; if (mystrtod(&p, &val)) val = render_context.font_size * ( 1 - pwr ) + val * pwr; else val = render_context.style->FontSize; if (render_context.font) change_font_size(val); } else if (mystrcmp(&p, "bord")) { double val; if (mystrtod(&p, &val)) val = render_context.border * ( 1 - pwr ) + val * pwr; else val = -1.; // reset to default change_border(val); } else if (mystrcmp(&p, "move")) { int x1, x2, y1, y2; long long t1, t2, delta_t, t; int x, y; double k; skip('('); x1 = strtol(p, &p, 10); skip(','); y1 = strtol(p, &p, 10); skip(','); x2 = strtol(p, &p, 10); skip(','); y2 = strtol(p, &p, 10); if (*p == ',') { skip(','); t1 = strtoll(p, &p, 10); skip(','); t2 = strtoll(p, &p, 10); mp_msg(MSGT_ASS, MSGL_DBG2, "movement6: (%d, %d) -> (%d, %d), (%" PRId64 " .. %" PRId64 ")\n", x1, y1, x2, y2, (int64_t)t1, (int64_t)t2); } else { t1 = 0; t2 = render_context.event->Duration; mp_msg(MSGT_ASS, MSGL_DBG2, "movement: (%d, %d) -> (%d, %d)\n", x1, y1, x2, y2); } skip(')'); delta_t = t2 - t1; t = frame_context.time - render_context.event->Start; if (t < t1) k = 0.; else if (t > t2) k = 1.; else k = ((double)(t - t1)) / delta_t; x = k * (x2 - x1) + x1; y = k * (y2 - y1) + y1; render_context.pos_x = x; render_context.pos_y = y; render_context.detect_collisions = 0; render_context.evt_type = EVENT_POSITIONED; } else if (mystrcmp(&p, "frx")) { double val; if (mystrtod(&p, &val)) { val *= M_PI / 180; render_context.frx = val * pwr + render_context.frx * (1-pwr); } else render_context.frx = 0.; } else if (mystrcmp(&p, "fry")) { double val; if (mystrtod(&p, &val)) { val *= M_PI / 180; render_context.fry = val * pwr + render_context.fry * (1-pwr); } else render_context.fry = 0.; } else if (mystrcmp(&p, "frz") || mystrcmp(&p, "fr")) { double val; if (mystrtod(&p, &val)) { val *= M_PI / 180; render_context.frz = val * pwr + render_context.frz * (1-pwr); } else render_context.frz = M_PI * render_context.style->Angle / 180.; } else if (mystrcmp(&p, "fn")) { char* start = p; char* family; skip_all('\\'); if (p > start) { family = malloc(p - start + 1); strncpy(family, start, p - start); family[p - start] = '\0'; } else family = strdup(render_context.style->FontName); if (render_context.family) free(render_context.family); render_context.family = family; update_font(); } else if (mystrcmp(&p, "alpha")) { uint32_t val; int i; if (strtocolor(&p, &val)) { unsigned char a = val >> 24; for (i = 0; i < 4; ++i) change_alpha(&render_context.c[i], a, pwr); } else { change_alpha(&render_context.c[0], render_context.style->PrimaryColour, pwr); change_alpha(&render_context.c[1], render_context.style->SecondaryColour, pwr); change_alpha(&render_context.c[2], render_context.style->OutlineColour, pwr); change_alpha(&render_context.c[3], render_context.style->BackColour, pwr); } // FIXME: simplify } else if (mystrcmp(&p, "an")) { int val; if (mystrtoi(&p, 10, &val) && val) { int v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment mp_msg(MSGT_ASS, MSGL_DBG2, "an %d\n", val); if (v != 0) v = 3 - v; val = ((val - 1) % 3) + 1; // horizontal alignment val += v*4; mp_msg(MSGT_ASS, MSGL_DBG2, "align %d\n", val); render_context.alignment = val; } else render_context.alignment = render_context.style->Alignment; } else if (mystrcmp(&p, "a")) { int val; if (mystrtoi(&p, 10, &val) && val) render_context.alignment = val; else render_context.alignment = render_context.style->Alignment; } else if (mystrcmp(&p, "pos")) { int v1, v2; skip('('); v1 = strtol(p, &p, 10); skip(','); v2 = strtol(p, &p, 10); skip(')'); mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%d, %d)\n", v1, v2); render_context.evt_type = EVENT_POSITIONED; render_context.detect_collisions = 0; render_context.pos_x = v1; render_context.pos_y = v2; } else if (mystrcmp(&p, "fad")) { int a1, a2, a3; long long t1, t2, t3, t4; if (*p == 'e') ++p; // either \fad or \fade skip('('); a1 = strtol(p, &p, 10); skip(','); a2 = strtol(p, &p, 10); if (*p == ')') { // 2-argument version (\fad, according to specs) // a1 and a2 are fade-in and fade-out durations t1 = 0; t4 = render_context.event->Duration; t2 = a1; t3 = t4 - a2; a1 = 0xFF; a2 = 0; a3 = 0xFF; } else { // 6-argument version (\fade) // a1 and a2 (and a3) are opacity values skip(','); a3 = strtol(p, &p, 10); skip(','); t1 = strtoll(p, &p, 10); skip(','); t2 = strtoll(p, &p, 10); skip(','); t3 = strtoll(p, &p, 10); skip(','); t4 = strtoll(p, &p, 10); } skip(')'); render_context.fade = interpolate_alpha(frame_context.time - render_context.event->Start, t1, t2, t3, t4, a1, a2, a3); } else if (mystrcmp(&p, "org")) { int v1, v2; skip('('); v1 = strtol(p, &p, 10); skip(','); v2 = strtol(p, &p, 10); skip(')'); mp_msg(MSGT_ASS, MSGL_DBG2, "org(%d, %d)\n", v1, v2); // render_context.evt_type = EVENT_POSITIONED; render_context.org_x = v1; render_context.org_y = v2; render_context.have_origin = 1; } else if (mystrcmp(&p, "t")) { double v[3]; int v1, v2; double v3;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?