ass_render.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 2,195 行 · 第 1/5 页
C
2,195 行
shift.x = pen.x & 63; shift.y = pen.y & 63; ass_font_set_transform(render_context.font, render_context.scale_x * frame_context.font_scale_x, render_context.scale_y, &shift ); get_outline_glyph(code, text_info.glyphs + text_info.length, &shift); text_info.glyphs[text_info.length].pos.x = pen.x >> 6; text_info.glyphs[text_info.length].pos.y = pen.y >> 6; pen.x += text_info.glyphs[text_info.length].advance.x; pen.x += double_to_d6(render_context.hspacing); pen.y += text_info.glyphs[text_info.length].advance.y; previous = code; text_info.glyphs[text_info.length].symbol = code; text_info.glyphs[text_info.length].linebreak = 0; for (i = 0; i < 4; ++i) { uint32_t clr = render_context.c[i]; change_alpha(&clr, mult_alpha(_a(clr), render_context.fade), 1.); text_info.glyphs[text_info.length].c[i] = clr; } text_info.glyphs[text_info.length].effect_type = render_context.effect_type; text_info.glyphs[text_info.length].effect_timing = render_context.effect_timing; text_info.glyphs[text_info.length].effect_skip_timing = render_context.effect_skip_timing; text_info.glyphs[text_info.length].be = render_context.be; text_info.glyphs[text_info.length].shadow = render_context.shadow; text_info.glyphs[text_info.length].frx = render_context.frx; text_info.glyphs[text_info.length].fry = render_context.fry; text_info.glyphs[text_info.length].frz = render_context.frz; ass_font_get_asc_desc(render_context.font, code, &text_info.glyphs[text_info.length].asc, &text_info.glyphs[text_info.length].desc); text_info.glyphs[text_info.length].asc *= render_context.scale_y; text_info.glyphs[text_info.length].desc *= render_context.scale_y; // fill bitmap_hash_key text_info.glyphs[text_info.length].hash_key.font = render_context.font; text_info.glyphs[text_info.length].hash_key.size = render_context.font_size; text_info.glyphs[text_info.length].hash_key.outline = render_context.border * 0xFFFF; text_info.glyphs[text_info.length].hash_key.scale_x = render_context.scale_x * 0xFFFF; text_info.glyphs[text_info.length].hash_key.scale_y = render_context.scale_y * 0xFFFF; text_info.glyphs[text_info.length].hash_key.frx = render_context.frx * 0xFFFF; text_info.glyphs[text_info.length].hash_key.fry = render_context.fry * 0xFFFF; text_info.glyphs[text_info.length].hash_key.frz = render_context.frz * 0xFFFF; text_info.glyphs[text_info.length].hash_key.bold = render_context.bold; text_info.glyphs[text_info.length].hash_key.italic = render_context.italic; text_info.glyphs[text_info.length].hash_key.ch = code; text_info.glyphs[text_info.length].hash_key.advance = shift; text_info.glyphs[text_info.length].hash_key.be = render_context.be; text_info.length++; render_context.effect_type = EF_NONE; render_context.effect_timing = 0; render_context.effect_skip_timing = 0; } if (text_info.length == 0) { // no valid symbols in the event; this can be smth like {comment} free_render_context(); return 1; } // depends on glyph x coordinates being monotonous, so it should be done before line wrap process_karaoke_effects(); // alignments alignment = render_context.alignment; halign = alignment & 3; valign = alignment & 12; MarginL = (event->MarginL) ? event->MarginL : render_context.style->MarginL; MarginR = (event->MarginR) ? event->MarginR : render_context.style->MarginR; MarginV = (event->MarginV) ? event->MarginV : render_context.style->MarginV; if (render_context.evt_type != EVENT_HSCROLL) { int max_text_width; // calculate max length of a line max_text_width = x2scr(frame_context.track->PlayResX - MarginR) - x2scr(MarginL); // rearrange text in several lines wrap_lines_smart(max_text_width); // align text last_break = -1; for (i = 1; i < text_info.length + 1; ++i) { // (text_info.length + 1) is the end of the last line if ((i == text_info.length) || text_info.glyphs[i].linebreak) { int width, shift = 0; glyph_info_t* first_glyph = text_info.glyphs + last_break + 1; glyph_info_t* last_glyph = text_info.glyphs + i - 1; while ((last_glyph > first_glyph) && ((last_glyph->symbol == '\n') || (last_glyph->symbol == 0))) last_glyph --; width = last_glyph->pos.x + d6_to_int(last_glyph->advance.x) - first_glyph->pos.x; if (halign == HALIGN_LEFT) { // left aligned, no action shift = 0; } else if (halign == HALIGN_RIGHT) { // right aligned shift = max_text_width - width; } else if (halign == HALIGN_CENTER) { // centered shift = (max_text_width - width) / 2; } for (j = last_break + 1; j < i; ++j) { text_info.glyphs[j].pos.x += shift; } last_break = i - 1; } } } else { // render_context.evt_type == EVENT_HSCROLL measure_text(); } // determing text bounding box compute_string_bbox(&text_info, &bbox); // determine device coordinates for text // x coordinate for everything except positioned events if (render_context.evt_type == EVENT_NORMAL || render_context.evt_type == EVENT_VSCROLL) { device_x = x2scr(MarginL); } else if (render_context.evt_type == EVENT_HSCROLL) { if (render_context.scroll_direction == SCROLL_RL) device_x = x2scr(frame_context.track->PlayResX - render_context.scroll_shift); else if (render_context.scroll_direction == SCROLL_LR) device_x = x2scr(render_context.scroll_shift) - (bbox.xMax - bbox.xMin); } // y coordinate for everything except positioned events if (render_context.evt_type == EVENT_NORMAL || render_context.evt_type == EVENT_HSCROLL) { if (valign == VALIGN_TOP) { // toptitle device_y = y2scr_top(MarginV) + d6_to_int(text_info.lines[0].asc); } else if (valign == VALIGN_CENTER) { // midtitle int scr_y = y2scr(frame_context.track->PlayResY / 2); device_y = scr_y - (bbox.yMax - bbox.yMin) / 2; } else { // subtitle int scr_y; if (valign != VALIGN_SUB) mp_msg(MSGT_ASS, MSGL_V, "Invalid valign, supposing 0 (subtitle)\n"); scr_y = y2scr_sub(frame_context.track->PlayResY - MarginV); device_y = scr_y; device_y -= d6_to_int(text_info.height); device_y += d6_to_int(text_info.lines[0].asc); } } else if (render_context.evt_type == EVENT_VSCROLL) { if (render_context.scroll_direction == SCROLL_TB) device_y = y2scr(render_context.clip_y0 + render_context.scroll_shift) - (bbox.yMax - bbox.yMin); else if (render_context.scroll_direction == SCROLL_BT) device_y = y2scr(render_context.clip_y1 - render_context.scroll_shift); } // positioned events are totally different if (render_context.evt_type == EVENT_POSITIONED) { int base_x = 0; int base_y = 0; mp_msg(MSGT_ASS, MSGL_DBG2, "positioned event at %d, %d\n", render_context.pos_x, render_context.pos_y); get_base_point(bbox, alignment, &base_x, &base_y); device_x = x2scr(render_context.pos_x) - base_x; device_y = y2scr(render_context.pos_y) - base_y; } // fix clip coordinates (they depend on alignment) render_context.clip_x0 = x2scr(render_context.clip_x0); render_context.clip_x1 = x2scr(render_context.clip_x1); if (render_context.evt_type == EVENT_NORMAL || render_context.evt_type == EVENT_HSCROLL || render_context.evt_type == EVENT_VSCROLL) { if (valign == VALIGN_TOP) { render_context.clip_y0 = y2scr_top(render_context.clip_y0); render_context.clip_y1 = y2scr_top(render_context.clip_y1); } else if (valign == VALIGN_CENTER) { render_context.clip_y0 = y2scr(render_context.clip_y0); render_context.clip_y1 = y2scr(render_context.clip_y1); } else if (valign == VALIGN_SUB) { render_context.clip_y0 = y2scr_sub(render_context.clip_y0); render_context.clip_y1 = y2scr_sub(render_context.clip_y1); } } else if (render_context.evt_type == EVENT_POSITIONED) { render_context.clip_y0 = y2scr(render_context.clip_y0); render_context.clip_y1 = y2scr(render_context.clip_y1); } // calculate rotation parameters { FT_Vector center; if (render_context.have_origin) { center.x = x2scr(render_context.org_x); center.y = y2scr(render_context.org_y); } else { int bx, by; get_base_point(bbox, alignment, &bx, &by); center.x = device_x + bx; center.y = device_y + by; } for (i = 0; i < text_info.length; ++i) { glyph_info_t* info = text_info.glyphs + i; if (info->hash_key.frx || info->hash_key.fry || info->hash_key.frz) { info->hash_key.shift_x = info->pos.x + device_x - center.x; info->hash_key.shift_y = - (info->pos.y + device_y - center.y); } else { info->hash_key.shift_x = 0; info->hash_key.shift_y = 0; } } } // convert glyphs to bitmaps for (i = 0; i < text_info.length; ++i) get_bitmap_glyph(text_info.glyphs + i); event_images->top = device_y - d6_to_int(text_info.lines[0].asc); event_images->height = d6_to_int(text_info.height); event_images->detect_collisions = render_context.detect_collisions; event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1; event_images->event = event; event_images->imgs = render_text(&text_info, device_x, device_y); free_render_context(); return 0;}/** * \brief deallocate image list * \param img list pointer */void ass_free_images(ass_image_t* img){ while (img) { ass_image_t* next = img->next; free(img); img = next; }}static void ass_reconfigure(ass_renderer_t* priv){ priv->render_id = ++last_render_id; ass_glyph_cache_reset(); ass_bitmap_cache_reset(); ass_free_images(priv->prev_images_root); priv->prev_images_root = 0;}void ass_set_frame_size(ass_renderer_t* priv, int w, int h){ 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; ass_reconfigure(priv); }}void ass_set_margins(ass_renderer_t* priv, int t, int b, int l, int r){ if (priv->settings.left_margin != l || priv->settings.right_margin != r || priv->settings.top_margin != t || priv->settings.bottom_margin != b) { priv->settings.left_margin = l; priv->settings.right_margin = r; priv->settings.top_margin = t; priv->settings.bottom_margin = b; ass_reconfigure(priv); }}void ass_set_use_margins(ass_renderer_t* priv, int use){ priv->settings.use_margins = use;}void ass_set_aspect_ratio(ass_renderer_t* priv, double ar){ if (priv->settings.aspect != ar) { priv->settings.aspect = ar; ass_reconfigure(priv); }}void ass_set_font_scale(ass_renderer_t* priv, double font_scale){ if (priv->settings.font_size_coeff != font_scale) { priv->settings.font_size_coeff = font_scale; ass_reconfigure(priv); }}void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht){ if (priv->settings.hinting != ht) { priv->settings.hinting = ht; ass_reconfigure(priv); }}void ass_set_line_spacing(ass_renderer_t* priv, double line_spacing){ priv->settings.line_spacing = line_spacing;}int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family){ if (priv->settings.default_font) free(priv->settings.default_font); if (priv->settings.default_family) free(priv->settings.default_family); priv->settings.default_font = default_font ? strdup(default_font) : 0; priv->settings.default_family = default_family ? strdup(default_family) : 0; if (priv->fontconfig_priv) fontconfig_done(priv->fontconfig_priv); priv->fontconfig_priv = fontconfig_init(priv->library, priv->ftlibrary, default_family, default_font); return !!priv->fontconfig_priv;}/** * \brief Start a new frame */static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long now){ ass_renderer = priv; global_settings = &priv->settings; if (!priv->settings.frame_width && !priv->settings.frame_height) return 1; // library not initialized frame_context.ass_priv = priv; frame_context.width = global_settings->frame_width; frame_context.height = global_settings->frame_height; frame_context.orig_width = global_settings->frame_width - global_settings->left_margin - global_settings->right_margin; frame_context.orig_height = global_settings->frame_height - global_settings->top_margin - global_settings->bottom_margin; frame_context.track = track; frame_context.time = now; ass_lazy_track_init(); frame_context.font_scale = global_settings->font_size_coeff * frame_context.orig_height / frame_context.track->PlayResY; frame_context.border_scale = ((double)frame_context.orig_height) / frame_context.track->PlayResY; if (frame_context.orig_width * track->PlayResY == frame_context.orig_height * track->PlayResX) frame_context.font_scale_x = 1.; else frame_context.font_scale_x = ((double)(frame_context.orig_width * track->PlayResY)) / (frame_context.orig_height * track->PlayResX); priv->prev_images_root = priv->images_root; priv->images_root = 0; return 0;}static int cmp_event_layer(const void* p1, const void* p2){ ass_event_t* e1 = ((event_images_t*)p1)->event; ass_event_t* e2 = ((event_images_t*)p2)->event; if (e1->Layer < e2->Layer) return -1; if (e1->Layer > e2->Layer) return 1; if (e1->ReadOrder < e2->ReadOrder) return -1; if (e1->ReadOrder > e2->ReadOrder) return 1; return 0;}#define MAX_EVENTS 100static render_priv_t* get_render_priv(ass_event_t* event){ if (!event->render_priv) event->render_priv = calloc(1, sizeof(render_priv_t)); // FIXME: check render_id if (ass_renderer->render_id != event->render_priv->render_id) { memset(event->render_priv, 0, sizeof(render_priv_t)); event->render_priv->render_id = ass_renderer->render_id; } return event->render_priv;}typedef struct segment_s { int a, b; // top and height} segment_t;static int overlap(segment_t* s1, segment_t* s2){ if (s1->a >= s2->b || s2->a >= s1->b) return 0; return 1;}static int cmp_segment(const void* p1, const void* p2){ return ((segment_t*)p1)->a - ((segment_t*)p2)->a;}static void shift_event(event_images_t* ei, int shift){ ass_image_t* cur = ei->imgs; while (cur) { cur->dst_y += shift; // clip top and bottom if (cur->dst_y < 0) { int clip = - cur->dst_y; cur->h -= clip; cur->bitmap += clip * cur->stride; cur->dst_y = 0; } if (cur->dst_y + cur->h >= frame_context.height) { int clip = cur->dst_y + cur->h - frame_context.height; cur->h -= clip; } if (cur->h <= 0) { cur->h = 0; cur->dst_y = 0; } cur = cur->next; } ei->top += shift;}// dir: 1 - move down// -1 - move up
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?