summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2015-07-23 15:28:42 -0400
committerNicolas Dufresne <nicolas.dufresne@collabora.co.uk>2015-07-24 16:43:59 -0400
commitd4759f05f17556984f392d2960b4c920ce053b94 (patch)
tree69b14db3bf8f7f8f224faf6c8cade2a0b38455e3
parent7569a2e932bc208000aff5967b87296ca2dd6f5d (diff)
basetextoverlay: Use the extents rectangle for positioning
the extents rectangle is what you need to know to properly position a buffer that has been rendered in a surface of the ink rectangle size. This patch make the placement on par with the placement we had before without having to over allocate. This patch also enable placement for vertical rendering. Note that the halginement, valighment and line-alignment default are set to the previous default when this property is set. This is for backward compatibility, you can change the value after setting vertical render. https://bugzilla.gnome.org/show_bug.cgi?id=728636
-rw-r--r--ext/pango/gstbasetextoverlay.c218
-rw-r--r--ext/pango/gstbasetextoverlay.h4
2 files changed, 132 insertions, 90 deletions
diff --git a/ext/pango/gstbasetextoverlay.c b/ext/pango/gstbasetextoverlay.c
index b649db64f..96b66f12b 100644
--- a/ext/pango/gstbasetextoverlay.c
+++ b/ext/pango/gstbasetextoverlay.c
@@ -255,8 +255,6 @@ static GstPadLinkReturn gst_base_text_overlay_text_pad_link (GstPad * pad,
static void gst_base_text_overlay_text_pad_unlink (GstPad * pad,
GstObject * parent);
static void gst_base_text_overlay_pop_text (GstBaseTextOverlay * overlay);
-static void gst_base_text_overlay_update_render_mode (GstBaseTextOverlay *
- overlay);
static void gst_base_text_overlay_finalize (GObject * object);
static void gst_base_text_overlay_set_property (GObject * object, guint prop_id,
@@ -319,6 +317,7 @@ gst_base_text_overlay_base_init (gpointer g_class)
fontmap = pango_cairo_font_map_get_default ();
klass->pango_context =
pango_font_map_create_context (PANGO_FONT_MAP (fontmap));
+ pango_context_set_base_gravity (klass->pango_context, PANGO_GRAVITY_SOUTH);
if (klass->pango_lock)
g_mutex_unlock (klass->pango_lock);
}
@@ -594,7 +593,6 @@ gst_base_text_overlay_init (GstBaseTextOverlay * overlay,
gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad);
g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- overlay->line_align = DEFAULT_PROP_LINE_ALIGNMENT;
overlay->layout =
pango_layout_new (GST_BASE_TEXT_OVERLAY_GET_CLASS
(overlay)->pango_context);
@@ -628,7 +626,10 @@ gst_base_text_overlay_init (GstBaseTextOverlay * overlay,
overlay->need_render = TRUE;
overlay->text_image = NULL;
overlay->use_vertical_render = DEFAULT_PROP_VERTICAL_RENDER;
- gst_base_text_overlay_update_render_mode (overlay);
+
+ overlay->line_align = DEFAULT_PROP_LINE_ALIGNMENT;
+ pango_layout_set_alignment (overlay->layout,
+ (PangoAlignment) overlay->line_align);
overlay->text_buffer = NULL;
overlay->text_linked = FALSE;
@@ -656,49 +657,20 @@ gst_base_text_overlay_init (GstBaseTextOverlay * overlay,
}
static void
-gst_base_text_overlay_update_wrap_mode (GstBaseTextOverlay * overlay)
+gst_base_text_overlay_set_wrap_mode (GstBaseTextOverlay * overlay, gint width)
{
if (overlay->wrap_mode == GST_BASE_TEXT_OVERLAY_WRAP_MODE_NONE) {
GST_DEBUG_OBJECT (overlay, "Set wrap mode NONE");
pango_layout_set_width (overlay->layout, -1);
} else {
- int width;
-
- if (overlay->auto_adjust_size) {
- width = DEFAULT_SCALE_BASIS * PANGO_SCALE;
- if (overlay->use_vertical_render) {
- width = width * (overlay->height - overlay->ypad * 2) / overlay->width;
- }
- } else {
- width =
- ((overlay->use_vertical_render ? overlay->height : overlay->width) -
- overlay->deltax) * PANGO_SCALE;
- }
+ width = width * PANGO_SCALE;
GST_DEBUG_OBJECT (overlay, "Set layout width %d", width);
GST_DEBUG_OBJECT (overlay, "Set wrap mode %d", overlay->wrap_mode);
pango_layout_set_width (overlay->layout, width);
- pango_layout_set_wrap (overlay->layout, (PangoWrapMode) overlay->wrap_mode);
}
-}
-
-static void
-gst_base_text_overlay_update_render_mode (GstBaseTextOverlay * overlay)
-{
- PangoMatrix matrix = PANGO_MATRIX_INIT;
- PangoContext *context = pango_layout_get_context (overlay->layout);
- if (overlay->use_vertical_render) {
- pango_matrix_rotate (&matrix, -90);
- pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO);
- pango_context_set_matrix (context, &matrix);
- pango_layout_set_alignment (overlay->layout, PANGO_ALIGN_LEFT);
- } else {
- pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH);
- pango_context_set_matrix (context, &matrix);
- pango_layout_set_alignment (overlay->layout,
- (PangoAlignment) overlay->line_align);
- }
+ pango_layout_set_wrap (overlay->layout, (PangoWrapMode) overlay->wrap_mode);
}
static gboolean
@@ -895,15 +867,12 @@ gst_base_text_overlay_setcaps (GstBaseTextOverlay * overlay, GstCaps * caps)
ret = gst_base_text_overlay_negotiate (overlay, caps);
GST_BASE_TEXT_OVERLAY_LOCK (overlay);
- g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+
if (!overlay->attach_compo_to_buffer &&
!gst_base_text_overlay_can_handle_caps (caps)) {
GST_DEBUG_OBJECT (overlay, "unsupported caps %" GST_PTR_FORMAT, caps);
ret = FALSE;
}
-
- gst_base_text_overlay_update_wrap_mode (overlay);
- g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
GST_BASE_TEXT_OVERLAY_UNLOCK (overlay);
return ret;
@@ -927,7 +896,6 @@ gst_base_text_overlay_set_property (GObject * object, guint prop_id,
case PROP_TEXT:
g_free (overlay->default_text);
overlay->default_text = g_value_dup_string (value);
- overlay->need_render = TRUE;
break;
case PROP_SHADING:
overlay->want_shading = g_value_get_boolean (value);
@@ -958,9 +926,6 @@ gst_base_text_overlay_set_property (GObject * object, guint prop_id,
break;
case PROP_WRAP_MODE:
overlay->wrap_mode = g_value_get_enum (value);
- g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- gst_base_text_overlay_update_wrap_mode (overlay);
- g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
break;
case PROP_FONT_DESC:
{
@@ -1009,14 +974,18 @@ gst_base_text_overlay_set_property (GObject * object, guint prop_id,
break;
case PROP_AUTO_ADJUST_SIZE:
overlay->auto_adjust_size = g_value_get_boolean (value);
- overlay->need_render = TRUE;
break;
case PROP_VERTICAL_RENDER:
overlay->use_vertical_render = g_value_get_boolean (value);
- g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- gst_base_text_overlay_update_render_mode (overlay);
- g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- overlay->need_render = TRUE;
+ if (overlay->use_vertical_render) {
+ overlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
+ overlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT;
+ overlay->line_align = GST_BASE_TEXT_OVERLAY_LINE_ALIGN_LEFT;
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ pango_layout_set_alignment (overlay->layout,
+ (PangoAlignment) overlay->line_align);
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ }
break;
case PROP_SHADING_VALUE:
overlay->shading_value = g_value_get_uint (value);
@@ -1432,30 +1401,26 @@ gst_base_text_overlay_get_pos (GstBaseTextOverlay * overlay,
gint * xpos, gint * ypos)
{
gint width, height;
- GstBaseTextOverlayVAlign valign;
- GstBaseTextOverlayHAlign halign;
-
- width = overlay->image_width / overlay->render_scale;
- height = overlay->image_height / overlay->render_scale;
- if (overlay->use_vertical_render)
- halign = GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT;
- else
- halign = overlay->halign;
+ width = overlay->logical_rect.width;
+ height = overlay->logical_rect.height;
- switch (halign) {
+ *xpos = overlay->ink_rect.x - overlay->logical_rect.x;
+ switch (overlay->halign) {
case GST_BASE_TEXT_OVERLAY_HALIGN_LEFT:
- *xpos = overlay->xpad;
+ *xpos += overlay->xpad;
+ *xpos = MAX (0, *xpos);
break;
case GST_BASE_TEXT_OVERLAY_HALIGN_CENTER:
- *xpos = (overlay->width - width) / 2;
+ *xpos += (overlay->width - width) / 2;
break;
case GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT:
- *xpos = overlay->width - width - overlay->xpad;
+ *xpos += overlay->width - width - overlay->xpad;
+ *xpos = MIN (overlay->width - overlay->ink_rect.width, *xpos);
break;
case GST_BASE_TEXT_OVERLAY_HALIGN_POS:
- *xpos = (gint) (overlay->width * overlay->xpos) - width / 2;
- *xpos = CLAMP (*xpos, 0, overlay->width - width);
+ *xpos += (gint) (overlay->width * overlay->xpos) - width / 2;
+ *xpos = CLAMP (*xpos, 0, overlay->width - overlay->ink_rect.width);
if (*xpos < 0)
*xpos = 0;
break;
@@ -1464,24 +1429,25 @@ gst_base_text_overlay_get_pos (GstBaseTextOverlay * overlay,
}
*xpos += overlay->deltax;
- if (overlay->use_vertical_render)
- valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
- else
- valign = overlay->valign;
-
- switch (valign) {
+ *ypos = overlay->ink_rect.y - overlay->logical_rect.y;
+ switch (overlay->valign) {
case GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM:
- *ypos = overlay->height - height - overlay->ypad;
+ /* This will be the same as baseline, if there is enough padding,
+ * otherwise it will avoid clipping the text */
+ *ypos += overlay->height - height - overlay->ypad;
+ *ypos = MIN (overlay->height - overlay->ink_rect.height, *ypos);
break;
case GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE:
- *ypos = overlay->height - (height + overlay->ypad);
+ *ypos += overlay->height - height - overlay->ypad;
+ /* Don't clip, this would not respect the base line */
break;
case GST_BASE_TEXT_OVERLAY_VALIGN_TOP:
- *ypos = overlay->ypad;
+ *ypos += overlay->ypad;
+ *ypos = MAX (0.0, *ypos);
break;
case GST_BASE_TEXT_OVERLAY_VALIGN_POS:
*ypos = (gint) (overlay->height * overlay->ypos) - height / 2;
- *ypos = CLAMP (*ypos, 0, overlay->height - height);
+ *ypos = CLAMP (*ypos, 0, overlay->height - overlay->ink_rect.height);
break;
case GST_BASE_TEXT_OVERLAY_VALIGN_CENTER:
*ypos = (overlay->height - height) / 2;
@@ -1491,6 +1457,8 @@ gst_base_text_overlay_get_pos (GstBaseTextOverlay * overlay,
break;
}
*ypos += overlay->deltay;
+
+ GST_DEBUG_OBJECT (overlay, "Placing overlay at (%d, %d)", *xpos, *ypos);
}
static inline void
@@ -1504,8 +1472,8 @@ gst_base_text_overlay_set_composition (GstBaseTextOverlay * overlay)
gst_base_text_overlay_get_pos (overlay, &xpos, &ypos);
- render_width = round (overlay->image_width / overlay->render_scale);
- render_height = round (overlay->image_height / overlay->render_scale);
+ render_width = overlay->ink_rect.width;
+ render_height = overlay->ink_rect.height;
GST_DEBUG ("updating composition for '%s' with window size %dx%d, "
"buffer size %dx%d, render size %dx%d and position (%d, %d)",
@@ -1568,10 +1536,12 @@ gst_base_text_overlay_render_pangocairo (GstBaseTextOverlay * overlay,
cairo_matrix_t cairo_matrix;
gint unscaled_width, unscaled_height;
gint width, height;
+ gboolean full_width = FALSE;
double scalef = 1.0;
double a, r, g, b;
gdouble shadow_offset = 0.0;
gdouble outline_offset = 0.0;
+ gint xpad = 0, ypad = 0;
GstBuffer *buffer;
GstMapInfo map;
@@ -1583,12 +1553,20 @@ gst_base_text_overlay_render_pangocairo (GstBaseTextOverlay * overlay,
}
if (overlay->draw_shadow)
- shadow_offset = overlay->shadow_offset;
+ shadow_offset = ceil (overlay->shadow_offset);
/* This value is uses as cairo line width, which is the diameter of a pen
* that is circular. That's why only half of it is used to offset */
if (overlay->draw_outline)
- outline_offset = overlay->outline_offset;
+ outline_offset = ceil (overlay->outline_offset);
+
+ if (overlay->halign == GST_BASE_TEXT_OVERLAY_HALIGN_LEFT ||
+ overlay->halign == GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT)
+ xpad = overlay->xpad;
+
+ if (overlay->valign == GST_BASE_TEXT_OVERLAY_VALIGN_TOP ||
+ overlay->valign == GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM)
+ ypad = overlay->ypad;
pango_layout_set_width (overlay->layout, -1);
/* set text on pango layout */
@@ -1600,23 +1578,86 @@ gst_base_text_overlay_render_pangocairo (GstBaseTextOverlay * overlay,
unscaled_width = ink_rect.width + shadow_offset + outline_offset;
width = ceil (unscaled_width * scalef);
- if (width + overlay->deltax >
- (overlay->use_vertical_render ? overlay->height : overlay->width)) {
- /*
- * subtitle image width is larger then overlay width
- * so rearrange overlay wrap mode.
- */
- gst_base_text_overlay_update_wrap_mode (overlay);
+ /*
+ * subtitle image width can be larger then overlay width
+ * so rearrange overlay wrap mode.
+ */
+ if (overlay->use_vertical_render) {
+ if (width + ypad > overlay->height) {
+ width = overlay->height - ypad;
+ full_width = TRUE;
+ }
+ } else if (width + xpad > overlay->width) {
+ width = overlay->width - xpad;
+ full_width = TRUE;
+ }
+
+ if (full_width) {
+ unscaled_width = width / scalef;
+ gst_base_text_overlay_set_wrap_mode (overlay,
+ unscaled_width - shadow_offset - outline_offset);
pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
+
unscaled_width = ink_rect.width + shadow_offset + outline_offset;
- width = overlay->width;
+ width = ceil (unscaled_width * scalef);
}
unscaled_height = ink_rect.height + shadow_offset + outline_offset;
height = ceil (unscaled_height * scalef);
- if (height > overlay->height) {
- height = overlay->height;
+ if (overlay->use_vertical_render) {
+ if (height + xpad > overlay->width) {
+ height = overlay->width - xpad;
+ unscaled_height = width / scalef;
+ }
+ } else if (height + ypad > overlay->height) {
+ height = overlay->height - ypad;
+ unscaled_height = height / scalef;
+ }
+
+ GST_DEBUG_OBJECT (overlay, "Rendering with ink rect (%d, %d) %dx%d and "
+ "locial rect (%d, %d) %dx%d", ink_rect.x, ink_rect.y, ink_rect.width,
+ ink_rect.height, logical_rect.x, logical_rect.y, logical_rect.width,
+ logical_rect.height);
+ GST_DEBUG_OBJECT (overlay, "Rendering with width %d and height %d "
+ "(shadow %f, outline %f)", unscaled_width, unscaled_height,
+ shadow_offset, outline_offset);
+
+
+ /* Save and scale the rectangles so get_pos() can place the text */
+ overlay->ink_rect.x =
+ ceil ((ink_rect.x - ceil (outline_offset / 2.0l)) * scalef);
+ overlay->ink_rect.y =
+ ceil ((ink_rect.y - ceil (outline_offset / 2.0l)) * scalef);
+ overlay->ink_rect.width = width;
+ overlay->ink_rect.height = height;
+
+ overlay->logical_rect.x =
+ ceil ((logical_rect.x - ceil (outline_offset / 2.0l)) * scalef);
+ overlay->logical_rect.y =
+ ceil ((logical_rect.y - ceil (outline_offset / 2.0l)) * scalef);
+ overlay->logical_rect.width =
+ ceil ((logical_rect.width + shadow_offset + outline_offset) * scalef);
+ overlay->logical_rect.height =
+ ceil ((logical_rect.height + shadow_offset + outline_offset) * scalef);
+
+ /* flip the rectangle if doing vertical render */
+ if (overlay->use_vertical_render) {
+ PangoRectangle tmp = overlay->ink_rect;
+
+ overlay->ink_rect.x = tmp.y;
+ overlay->ink_rect.y = tmp.x;
+ overlay->ink_rect.width = tmp.height;
+ overlay->ink_rect.height = tmp.width;
+ /* We want the top left corect, but we now have the top right */
+ overlay->ink_rect.x += overlay->ink_rect.width;
+
+ tmp = overlay->logical_rect;
+ overlay->logical_rect.x = tmp.y;
+ overlay->logical_rect.y = tmp.x;
+ overlay->logical_rect.width = tmp.height;
+ overlay->logical_rect.height = tmp.width;
+ overlay->logical_rect.x += overlay->logical_rect.width;
}
/* scale to reported window size */
@@ -1741,7 +1782,6 @@ gst_base_text_overlay_render_pangocairo (GstBaseTextOverlay * overlay,
overlay->image_width = width;
if (height != 0)
overlay->image_height = height;
- overlay->baseline_y = ink_rect.y;
g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
gst_base_text_overlay_set_composition (overlay);
diff --git a/ext/pango/gstbasetextoverlay.h b/ext/pango/gstbasetextoverlay.h
index 1fb6d9987..ab9a8afeb 100644
--- a/ext/pango/gstbasetextoverlay.h
+++ b/ext/pango/gstbasetextoverlay.h
@@ -194,7 +194,9 @@ struct _GstBaseTextOverlay {
gdouble shadow_offset;
gdouble outline_offset;
- gint baseline_y;
+
+ PangoRectangle ink_rect;
+ PangoRectangle logical_rect;
gboolean attach_compo_to_buffer;
GstVideoOverlayComposition *composition;