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 + -
显示快捷键?