ass_render.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 2,195 行 · 第 1/5 页
C
2,195 行
int cnt; long long t1, t2, t, delta_t; double k; skip('('); for (cnt = 0; cnt < 3; ++cnt) { if (*p == '\\') break; v[cnt] = strtod(p, &p); skip(','); } if (cnt == 3) { v1 = v[0]; v2 = v[1]; v3 = v[2]; } else if (cnt == 2) { v1 = v[0]; v2 = v[1]; v3 = 1.; } else if (cnt == 1) { v1 = 0; v2 = render_context.event->Duration; v3 = v[0]; } else { // cnt == 0 v1 = 0; v2 = render_context.event->Duration; v3 = 1.; } render_context.detect_collisions = 0; t1 = v1; t2 = v2; delta_t = v2 - v1; if (v3 < 0.) v3 = 0.; t = frame_context.time - render_context.event->Start; // FIXME: move to render_context if (t <= t1) k = 0.; else if (t >= t2) k = 1.; else { assert(delta_t != 0.); k = pow(((double)(t - t1)) / delta_t, v3); } while (*p == '\\') p = parse_tag(p, k); // maybe k*pwr ? no, specs forbid nested \t's skip_all(')'); // FIXME: better skip(')'), but much more tags support required } else if (mystrcmp(&p, "clip")) { int x0, y0, x1, y1; int res = 1; skip('('); res &= mystrtoi(&p, 10, &x0); skip(','); res &= mystrtoi(&p, 10, &y0); skip(','); res &= mystrtoi(&p, 10, &x1); skip(','); res &= mystrtoi(&p, 10, &y1); skip(')'); if (res) { render_context.clip_x0 = render_context.clip_x0 * (1-pwr) + x0 * pwr; render_context.clip_x1 = render_context.clip_x1 * (1-pwr) + x1 * pwr; render_context.clip_y0 = render_context.clip_y0 * (1-pwr) + y0 * pwr; render_context.clip_y1 = render_context.clip_y1 * (1-pwr) + y1 * pwr; } else { render_context.clip_x0 = 0; render_context.clip_y0 = 0; render_context.clip_x1 = frame_context.track->PlayResX; render_context.clip_y1 = frame_context.track->PlayResY; } } else if (mystrcmp(&p, "c")) { uint32_t val; if (!strtocolor(&p, &val)) val = render_context.style->PrimaryColour; mp_msg(MSGT_ASS, MSGL_DBG2, "color: %X\n", val); change_color(&render_context.c[0], val, pwr); } else if ((*p >= '1') && (*p <= '4') && (++p) && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) { char n = *(p-2); int cidx = n - '1'; char cmd = *(p-1); uint32_t val; assert((n >= '1') && (n <= '4')); if (!strtocolor(&p, &val)) switch(n) { case '1': val = render_context.style->PrimaryColour; break; case '2': val = render_context.style->SecondaryColour; break; case '3': val = render_context.style->OutlineColour; break; case '4': val = render_context.style->BackColour; break; default : val = 0; break; // impossible due to assert; avoid compilation warning } switch (cmd) { case 'c': change_color(render_context.c + cidx, val, pwr); break; case 'a': change_alpha(render_context.c + cidx, val >> 24, pwr); break; default: mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_BadCommand, n, cmd); break; } mp_msg(MSGT_ASS, MSGL_DBG2, "single c/a at %f: %c%c = %X \n", pwr, n, cmd, render_context.c[cidx]); } else if (mystrcmp(&p, "r")) { reset_render_context(); } else if (mystrcmp(&p, "be")) { int val; if (mystrtoi(&p, 10, &val)) render_context.be = val ? 1 : 0; else render_context.be = 0; } else if (mystrcmp(&p, "b")) { int b; if (mystrtoi(&p, 10, &b)) { if (pwr >= .5) render_context.bold = b; } else render_context.bold = render_context.style->Bold; update_font(); } else if (mystrcmp(&p, "i")) { int i; if (mystrtoi(&p, 10, &i)) { if (pwr >= .5) render_context.italic = i; } else render_context.italic = render_context.style->Italic; update_font(); } else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) { int val = strtol(p, &p, 10); render_context.effect_type = EF_KARAOKE_KF; if (render_context.effect_timing) render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_timing = val * 10; } else if (mystrcmp(&p, "ko")) { int val = strtol(p, &p, 10); render_context.effect_type = EF_KARAOKE_KO; if (render_context.effect_timing) render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_timing = val * 10; } else if (mystrcmp(&p, "k")) { int val = strtol(p, &p, 10); render_context.effect_type = EF_KARAOKE; if (render_context.effect_timing) render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_timing = val * 10; } else if (mystrcmp(&p, "shad")) { int val; if (mystrtoi(&p, 10, &val)) render_context.shadow = val; else render_context.shadow = render_context.style->Shadow; } return p;#undef skip#undef skip_all}/** * \brief Get next ucs4 char from string, parsing and executing style overrides * \param str string pointer * \return ucs4 code of the next char * On return str points to the unparsed part of the string */static unsigned get_next_char(char** str){ char* p = *str; unsigned chr; if (*p == '{') { // '\0' goes here p++; while (1) { p = parse_tag(p, 1.); if (*p == '}') { // end of tag p++; if (*p == '{') { p++; continue; } else break; } else if (*p != '\\') mp_msg(MSGT_ASS, MSGL_V, "Unable to parse: \"%s\" \n", p); if (*p == 0) break; } } if (*p == '\t') { ++p; *str = p; return ' '; } if (*p == '\\') { if ((*(p+1) == 'N') || ((*(p+1) == 'n') && (frame_context.track->WrapStyle == 2))) { p += 2; *str = p; return '\n'; } else if (*(p+1) == 'n') { p += 2; *str = p; return ' '; } } chr = utf8_get_char(&p); *str = p; return chr;}static void apply_transition_effects(ass_event_t* event){ int v[4]; int cnt; char* p = event->Effect; if (!p || !*p) return; cnt = 0; while (cnt < 4 && (p = strchr(p, ';'))) { v[cnt++] = atoi(++p); } if (strncmp(event->Effect, "Banner;", 7) == 0) { int delay; if (cnt < 1) { mp_msg(MSGT_ASS, MSGL_V, "Error parsing effect: %s \n", event->Effect); return; } if (cnt >= 2 && v[1] == 0) // right-to-left render_context.scroll_direction = SCROLL_RL; else // left-to-right render_context.scroll_direction = SCROLL_LR; delay = v[0]; if (delay == 0) delay = 1; // ? render_context.scroll_shift = (frame_context.time - render_context.event->Start) / delay; render_context.evt_type = EVENT_HSCROLL; return; } if (strncmp(event->Effect, "Scroll up;", 10) == 0) { render_context.scroll_direction = SCROLL_BT; } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { render_context.scroll_direction = SCROLL_TB; } else { mp_msg(MSGT_ASS, MSGL_V, "Unknown transition effect: %s \n", event->Effect); return; } // parse scroll up/down parameters { int delay; int y0, y1; if (cnt < 3) { mp_msg(MSGT_ASS, MSGL_V, "Error parsing effect: %s \n", event->Effect); return; } delay = v[2]; if (delay == 0) delay = 1; // ? render_context.scroll_shift = (frame_context.time - render_context.event->Start) / delay; if (v[0] < v[1]) { y0 = v[0]; y1 = v[1]; } else { y0 = v[1]; y1 = v[0]; } if (y1 == 0) y1 = frame_context.track->PlayResY; // y0=y1=0 means fullscreen scrolling render_context.clip_y0 = y0; render_context.clip_y1 = y1; render_context.evt_type = EVENT_VSCROLL; render_context.detect_collisions = 0; }}/** * \brief partially reset render_context to style values * Works like {\r}: resets some style overrides */static void reset_render_context(void){ render_context.c[0] = render_context.style->PrimaryColour; render_context.c[1] = render_context.style->SecondaryColour; render_context.c[2] = render_context.style->OutlineColour; render_context.c[3] = render_context.style->BackColour; render_context.font_size = render_context.style->FontSize; if (render_context.family) free(render_context.family); render_context.family = strdup(render_context.style->FontName); render_context.bold = render_context.style->Bold; render_context.italic = render_context.style->Italic; update_font(); change_border(-1.); render_context.scale_x = render_context.style->ScaleX; render_context.scale_y = render_context.style->ScaleY; render_context.hspacing = render_context.style->Spacing; render_context.be = 0; render_context.shadow = render_context.style->Shadow; render_context.frx = render_context.fry = 0.; render_context.frz = M_PI * render_context.style->Angle / 180.; // FIXME: does not reset unsupported attributes.}/** * \brief Start new event. Reset render_context. */static void init_render_context(ass_event_t* event){ render_context.event = event; render_context.style = frame_context.track->styles + event->Style; reset_render_context(); render_context.evt_type = EVENT_NORMAL; render_context.alignment = render_context.style->Alignment; render_context.pos_x = 0; render_context.pos_y = 0; render_context.org_x = 0; render_context.org_y = 0; render_context.have_origin = 0; render_context.clip_x0 = 0; render_context.clip_y0 = 0; render_context.clip_x1 = frame_context.track->PlayResX; render_context.clip_y1 = frame_context.track->PlayResY; render_context.detect_collisions = 1; render_context.fade = 0; render_context.effect_type = EF_NONE; render_context.effect_timing = 0; render_context.effect_skip_timing = 0; apply_transition_effects(event);}static void free_render_context(void){}/** * \brief Get normal and outline (border) glyphs * \param symbol ucs4 char * \param info out: struct filled with extracted data * \param advance subpixel shift vector used for cache lookup * Tries to get both glyphs from cache. * If they can't be found, gets a glyph from font face, generates outline with FT_Stroker, * and add them to cache. * The glyphs are returned in info->glyph and info->outline_glyph */static void get_outline_glyph(int symbol, glyph_info_t* info, FT_Vector* advance){ int error; glyph_hash_val_t* val; glyph_hash_key_t key; key.font = render_context.font; key.size = render_context.font_size; key.ch = symbol; key.scale_x = (render_context.scale_x * 0xFFFF); key.scale_y = (render_context.scale_y * 0xFFFF); key.advance = *advance; key.bold = render_context.bold; key.italic = render_context.italic; key.outline = render_context.border * 0xFFFF; info->glyph = info->outline_glyph = 0; val = cache_find_glyph(&key); if (val) { FT_Glyph_Copy(val->glyph, &info->glyph); if (val->outline_glyph) FT_Glyph_Copy(val->outline_glyph, &info->outline_glyph); info->bbox = val->bbox_scaled; info->advance.x = val->advance.x; info->advance.y = val->advance.y; } else { glyph_hash_val_t v; info->glyph = ass_font_get_glyph(frame_context.ass_priv->fontconfig_priv, render_context.font, symbol, global_settings->hinting); if (!info->glyph) return; info->advance.x = d16_to_d6(info->glyph->advance.x); info->advance.y = d16_to_d6(info->glyph->advance.y); FT_Glyph_Get_CBox( info->glyph, FT_GLYPH_BBOX_PIXELS, &info->bbox); if (render_context.stroker) { info->outline_glyph = info->glyph; error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_context.stroker, 0 , 0 ); // don't destroy original if (error) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error); } } memset(&v, 0, sizeof(v)); FT_Glyph_Copy(info->glyph, &v.glyph); if (info->outline_glyph) FT_Glyph_Copy(info->outline_glyph, &v.outline_glyph); v.advance = info->advance; v.bbox_scaled = info->bbox; cache_add_glyph(&key, &v); }}static void transform_3d(FT_Vector shift, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz);/** * \brief Get bitmaps for a glyph * \param info glyph info * Tries to get glyph bitmaps from bitmap cache. * If they can't be found, they are generated by rotating and rendering the glyph. * After that, bitmaps are added to the cache. * They are returned in info->bm (glyph), info->bm_o (outline) and info->bm_s (shadow). */static void get_bitmap_glyph(glyph_info_t* info){ bitmap_hash_val_t* val; bitmap_hash_key_t* key = &info->hash_key; val = cache_find_bitmap(key);/* val = 0; */ if (val) { info->bm = val->bm; info->bm_o = val->bm_o; info->bm_s = val->bm_s; } else { FT_Vector shift; bitmap_hash_val_t hash_val; int error; info->bm = info->bm_o = info->bm_s = 0; if (info->glyph && info->symbol != '\n' && info->symbol != 0) { // calculating rotation shift vector (from rotation origin to the glyph basepoint) shift.x = int_to_d6(info->hash_key.shift_x); shift.y = int_to_d6(info->hash_key.shift_y); // apply rotation transform_3d(shift, &info->glyph, &info->outline_glyph, info->frx, info->fry, info->frz); // render glyph error = glyph_to_bitmap(ass_renderer->synth_priv, info->glyph, info->outline_glyph, &info->bm, &info->bm_o, &info->bm_s, info->be); if (error) info->symbol = 0; // add bitmaps to cache hash_val.bm_o = info->bm_o; hash_val.bm = info->bm; hash_val.bm_s = info->bm_s; cache_add_bitmap(&(info->hash_key), &hash_val); } } // deallocate glyphs if (info->glyph) FT_Done_Glyph(info->glyph); if (info->outline_glyph) FT_Done_Glyph(info->outline_glyph);}/**
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?