*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
/**
#endif
#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
#include "gstbasetextoverlay.h"
#include "gsttextoverlay.h"
#define DEFAULT_PROP_SHADING FALSE
#define DEFAULT_PROP_VALIGNMENT GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE
#define DEFAULT_PROP_HALIGNMENT GST_BASE_TEXT_OVERLAY_HALIGN_CENTER
-#define DEFAULT_PROP_VALIGN "baseline"
-#define DEFAULT_PROP_HALIGN "center"
#define DEFAULT_PROP_XPAD 25
#define DEFAULT_PROP_YPAD 25
#define DEFAULT_PROP_DELTAX 0
#define MINIMUM_OUTLINE_OFFSET 1.0
#define DEFAULT_SCALE_BASIS 640
-#define COMP_Y(ret, r, g, b) \
-{ \
- ret = (int) (((19595 * r) >> 16) + ((38470 * g) >> 16) + ((7471 * b) >> 16)); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define COMP_U(ret, r, g, b) \
-{ \
- ret = (int) (-((11059 * r) >> 16) - ((21709 * g) >> 16) + ((32768 * b) >> 16) + 128); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define COMP_V(ret, r, g, b) \
-{ \
- ret = (int) (((32768 * r) >> 16) - ((27439 * g) >> 16) - ((5329 * b) >> 16) + 128); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define BLEND(ret, alpha, v0, v1) \
-{ \
- ret = (v0 * alpha + v1 * (255 - alpha)) / 255; \
-}
-
-#define OVER(ret, alphaA, Ca, alphaB, Cb, alphaNew) \
-{ \
- gint _tmp; \
- _tmp = (Ca * alphaA + Cb * alphaB * (255 - alphaA) / 255) / alphaNew; \
- ret = CLAMP (_tmp, 0, 255); \
-}
-
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-# define CAIRO_ARGB_A 3
-# define CAIRO_ARGB_R 2
-# define CAIRO_ARGB_G 1
-# define CAIRO_ARGB_B 0
-#else
-# define CAIRO_ARGB_A 0
-# define CAIRO_ARGB_R 1
-# define CAIRO_ARGB_G 2
-# define CAIRO_ARGB_B 3
-#endif
-
enum
{
PROP_0,
PROP_TEXT,
PROP_SHADING,
- PROP_VALIGN, /* deprecated */
- PROP_HALIGN, /* deprecated */
PROP_HALIGNMENT,
PROP_VALIGNMENT,
PROP_XPAD,
PROP_LAST
};
-#define VIDEO_FORMATS "{ BGRx, RGBx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, \
- I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, \
- Y800, Y16, NV12, NV21, UYVP, A420, YUV9, IYU1 }"
+#define VIDEO_FORMATS GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS
static GstStaticPadTemplate src_template_factory =
GST_STATIC_PAD_TEMPLATE ("src",
static GstFlowReturn gst_base_text_overlay_text_chain (GstPad * pad,
GstObject * parent, GstBuffer * buffer);
static GstPadLinkReturn gst_base_text_overlay_text_pad_link (GstPad * pad,
- GstPad * peer);
-static void gst_base_text_overlay_text_pad_unlink (GstPad * pad);
+ GstObject * parent, GstPad * peer);
+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);
g_param_spec_enum ("halignment", "horizontal alignment",
"Horizontal alignment of the text", GST_TYPE_BASE_TEXT_OVERLAY_HALIGN,
DEFAULT_PROP_HALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGN,
- g_param_spec_string ("valign", "vertical alignment",
- "Vertical alignment of the text (deprecated; use valignment)",
- DEFAULT_PROP_VALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGN,
- g_param_spec_string ("halign", "horizontal alignment",
- "Horizontal alignment of the text (deprecated; use halignment)",
- DEFAULT_PROP_HALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPAD,
g_param_spec_int ("xpad", "horizontal paddding",
"Horizontal paddding when using left/right alignment", 0, G_MAXINT,
"Shift Y position up or down. Unit is pixels.", G_MININT, G_MAXINT,
DEFAULT_PROP_DELTAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseTextOverlay:xpos
+ * GstBaseTextOverlay:xpos:
*
* Horizontal position of the rendered text when using positioned alignment.
- *
- * Since: 0.10.31
- **/
+ */
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPOS,
g_param_spec_double ("xpos", "horizontal position",
"Horizontal position when using position alignment", 0, 1.0,
DEFAULT_PROP_XPOS,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseTextOverlay:ypos
+ * GstBaseTextOverlay:ypos:
*
* Vertical position of the rendered text when using positioned alignment.
- *
- * Since: 0.10.31
- **/
+ */
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPOS,
g_param_spec_double ("ypos", "vertical position",
"Vertical position when using position alignment", 0, 1.0,
"for syntax.", DEFAULT_PROP_FONT_DESC,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseTextOverlay:color
+ * GstBaseTextOverlay:color:
*
* Color of the rendered text.
- *
- * Since: 0.10.31
- **/
+ */
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COLOR,
g_param_spec_uint ("color", "Color",
"Color to use for text (big-endian ARGB).", 0, G_MAXUINT32,
DEFAULT_PROP_COLOR,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
/**
- * GstTextOverlay:outline-color
+ * GstTextOverlay:outline-color:
*
* Color of the outline of the rendered text.
- *
- * Since: 0.10.35
- **/
+ */
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_OUTLINE_COLOR,
g_param_spec_uint ("outline-color", "Text Outline Color",
"Color to use for outline the text (big-endian ARGB).", 0,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseTextOverlay:line-alignment
+ * GstBaseTextOverlay:line-alignment:
*
* Alignment of text lines relative to each other (for multi-line text)
- *
- * Since: 0.10.15
- **/
+ */
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINE_ALIGNMENT,
g_param_spec_enum ("line-alignment", "line alignment",
"Alignment of text lines relative to each other.",
GST_TYPE_BASE_TEXT_OVERLAY_LINE_ALIGN, DEFAULT_PROP_LINE_ALIGNMENT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseTextOverlay:silent
+ * GstBaseTextOverlay:silent:
*
* If set, no text is rendered. Useful to switch off text rendering
* temporarily without removing the textoverlay element from the pipeline.
- *
- * Since: 0.10.15
- **/
+ */
/* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
g_param_spec_boolean ("silent", "silent",
DEFAULT_PROP_SILENT,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseTextOverlay:wait-text
+ * GstBaseTextOverlay:wait-text:
*
* If set, the video will block until a subtitle is received on the text pad.
* If video and subtitles are sent in sync, like from the same demuxer, this
* property should be set.
- *
- * Since: 0.10.20
- **/
+ */
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WAIT_TEXT,
g_param_spec_boolean ("wait-text", "Wait Text",
"Whether to wait for subtitles",
GST_DEBUG_FUNCPTR (gst_base_text_overlay_video_chain));
gst_pad_set_query_function (overlay->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_base_text_overlay_video_query));
+ GST_PAD_SET_PROXY_ALLOCATION (overlay->video_sinkpad);
gst_element_add_pad (GST_ELEMENT (overlay), overlay->video_sinkpad);
template =
if (template) {
/* text sink */
overlay->text_sinkpad = gst_pad_new_from_template (template, "text_sink");
- gst_object_unref (template);
gst_pad_set_event_function (overlay->text_sinkpad,
GST_DEBUG_FUNCPTR (gst_base_text_overlay_text_event));
gst_base_text_overlay_setcaps_txt (GstBaseTextOverlay * overlay, GstCaps * caps)
{
GstStructure *structure;
+ const gchar *format;
structure = gst_caps_get_structure (caps, 0);
- overlay->have_pango_markup =
- gst_structure_has_name (structure, "text/x-pango-markup");
+ format = gst_structure_get_string (structure, "format");
+ overlay->have_pango_markup = (strcmp (format, "pango-markup") == 0);
return TRUE;
}
/* FIXME: upstream nego (e.g. when the video window is resized) */
+/* only negotiate/query video overlay composition support for now */
+static gboolean
+gst_base_text_overlay_negotiate (GstBaseTextOverlay * overlay)
+{
+ GstCaps *target;
+ GstQuery *query;
+ gboolean attach = FALSE;
+
+ GST_DEBUG_OBJECT (overlay, "performing negotiation");
+
+ target = gst_pad_get_current_caps (overlay->srcpad);
+
+ if (!target || gst_caps_is_empty (target))
+ goto no_format;
+
+ /* find supported meta */
+ query = gst_query_new_allocation (target, TRUE);
+
+ if (!gst_pad_peer_query (overlay->srcpad, query)) {
+ /* no problem, we use the query defaults */
+ GST_DEBUG_OBJECT (overlay, "ALLOCATION query failed");
+ }
+
+ if (gst_query_find_allocation_meta (query,
+ GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL))
+ attach = TRUE;
+
+ overlay->attach_compo_to_buffer = attach;
+
+ gst_query_unref (query);
+ gst_caps_unref (target);
+
+ return TRUE;
+
+no_format:
+ {
+ if (target)
+ gst_caps_unref (target);
+ return FALSE;
+ }
+}
+
static gboolean
gst_base_text_overlay_setcaps (GstBaseTextOverlay * overlay, GstCaps * caps)
{
ret = gst_pad_set_caps (overlay->srcpad, caps);
if (ret) {
-#if 0
- GstStructure *structure;
-#endif
-
GST_BASE_TEXT_OVERLAY_LOCK (overlay);
g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
-
- /* FIXME Use the query to the sink to do that when implemented */
- /* Update wether to attach composition to buffer or do the composition
- * ourselves */
-#if 0
- structure = gst_caps_get_structure (caps, 0);
- if (gst_structure_has_name (structure, "video/x-surface"))
- overlay->attach_compo_to_buffer = TRUE;
- else
- overlay->attach_compo_to_buffer = FALSE;
-#else
- GST_FIXME_OBJECT (overlay, "query downstream for overlay support");
- overlay->attach_compo_to_buffer = FALSE;
-#endif
-
+ gst_base_text_overlay_negotiate (overlay);
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);
case PROP_YPOS:
overlay->ypos = g_value_get_double (value);
break;
- case PROP_HALIGN:{
- const gchar *s = g_value_get_string (value);
-
- if (s && g_ascii_strcasecmp (s, "left") == 0)
- overlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_LEFT;
- else if (s && g_ascii_strcasecmp (s, "center") == 0)
- overlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_CENTER;
- else if (s && g_ascii_strcasecmp (s, "right") == 0)
- overlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT;
- else
- g_warning ("Invalid value '%s' for textoverlay property 'halign'",
- GST_STR_NULL (s));
- break;
- }
- case PROP_VALIGN:{
- const gchar *s = g_value_get_string (value);
-
- if (s && g_ascii_strcasecmp (s, "baseline") == 0)
- overlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE;
- else if (s && g_ascii_strcasecmp (s, "bottom") == 0)
- overlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM;
- else if (s && g_ascii_strcasecmp (s, "top") == 0)
- overlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
- else
- g_warning ("Invalid value '%s' for textoverlay property 'valign'",
- GST_STR_NULL (s));
- break;
- }
case PROP_VALIGNMENT:
overlay->valign = g_value_get_enum (value);
break;
break;
}
default:
- ret = gst_pad_peer_query (overlay->video_sinkpad, query);
+ ret = gst_pad_query_default (pad, parent, query);
break;
}
gst_base_text_overlay_get_pos (overlay, &xpos, &ypos);
if (overlay->text_image) {
- rectangle = gst_video_overlay_rectangle_new_argb (overlay->text_image,
- overlay->image_width, overlay->image_height, 4 * overlay->image_width,
+ gst_buffer_add_video_meta (overlay->text_image, GST_VIDEO_FRAME_FLAG_NONE,
+ GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB,
+ overlay->image_width, overlay->image_height);
+ rectangle = gst_video_overlay_rectangle_new_raw (overlay->text_image,
xpos, ypos, overlay->image_width, overlay->image_height,
GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
}
}
+static gboolean
+gst_text_overlay_filter_foreground_attr (PangoAttribute * attr, gpointer data)
+{
+ if (attr->klass->type == PANGO_ATTR_FOREGROUND) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
static void
gst_base_text_overlay_render_pangocairo (GstBaseTextOverlay * overlay,
const gchar * string, gint textlen)
*/
/* draw shadow text */
- cairo_save (cr);
- cairo_translate (cr, overlay->shadow_offset, overlay->shadow_offset);
- cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
- pango_cairo_show_layout (cr, overlay->layout);
- cairo_restore (cr);
+ {
+ PangoAttrList *origin_attr, *filtered_attr, *temp_attr;
+
+ /* Store a ref on the original attributes for later restoration */
+ origin_attr =
+ pango_attr_list_ref (pango_layout_get_attributes (overlay->layout));
+ /* Take a copy of the original attributes, because pango_attr_list_filter
+ * modifies the passed list */
+ temp_attr = pango_attr_list_copy (origin_attr);
+ filtered_attr =
+ pango_attr_list_filter (temp_attr,
+ gst_text_overlay_filter_foreground_attr, NULL);
+ pango_attr_list_unref (temp_attr);
+
+ cairo_save (cr);
+ cairo_translate (cr, overlay->shadow_offset, overlay->shadow_offset);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
+ pango_layout_set_attributes (overlay->layout, filtered_attr);
+ pango_cairo_show_layout (cr, overlay->layout);
+ pango_layout_set_attributes (overlay->layout, origin_attr);
+ pango_attr_list_unref (filtered_attr);
+ pango_attr_list_unref (origin_attr);
+ cairo_restore (cr);
+ }
a = (overlay->outline_color >> 24) & 0xff;
r = (overlay->outline_color >> 16) & 0xff;
gst_base_text_overlay_set_composition (overlay);
}
-#define BOX_XPAD 6
-#define BOX_YPAD 6
-
static inline void
gst_base_text_overlay_shade_planar_Y (GstBaseTextOverlay * overlay,
GstVideoFrame * dest, gint x0, gint x1, gint y0, gint y1)
dest_stride = dest->info.stride[0];
dest_ptr = dest->data[0];
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
for (i = y0; i < y1; ++i) {
for (j = x0; j < x1; ++j) {
gint y = dest_ptr[(i * dest_stride) + j] + overlay->shading_value;
dest_ptr = GST_VIDEO_FRAME_COMP_DATA (dest, 0);
pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (dest, 0);
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
if (x0 != 0)
x0 = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (dest->info.finfo, 0, x0);
if (x1 != 0)
dest_ptr = dest->data[0];
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
for (i = y0; i < y1; i++) {
for (j = x0; j < x1; j++) {
gint y, y_pos, k;
}
}
+/* FIXME: orcify */
+static void
+gst_base_text_overlay_shade_rgb24 (GstBaseTextOverlay * overlay,
+ GstVideoFrame * frame, gint x0, gint x1, gint y0, gint y1)
+{
+ const int pstride = 3;
+ gint y, x, stride, shading_val, tmp;
+ guint8 *p;
+
+ shading_val = overlay->shading_value;
+ stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+ for (y = y0; y < y1; ++y) {
+ p = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+ p += (y * stride) + (x0 * pstride);
+ for (x = x0; x < x1; ++x) {
+ tmp = *p + shading_val;
+ *p++ = CLAMP (tmp, 0, 255);
+ tmp = *p + shading_val;
+ *p++ = CLAMP (tmp, 0, 255);
+ tmp = *p + shading_val;
+ *p++ = CLAMP (tmp, 0, 255);
+ }
+ }
+}
+
+static void
+gst_base_text_overlay_shade_IYU1 (GstBaseTextOverlay * overlay,
+ GstVideoFrame * frame, gint x0, gint x1, gint y0, gint y1)
+{
+ gint y, x, stride, shading_val, tmp;
+ guint8 *p;
+
+ shading_val = overlay->shading_value;
+ stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+ /* IYU1: packed 4:1:1 YUV (Cb-Y0-Y1-Cr-Y2-Y3 ...) */
+ for (y = y0; y < y1; ++y) {
+ p = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+ /* move to Y0 or Y1 (we pretend the chroma is the last of the 3 bytes) */
+ /* FIXME: we're not pixel-exact here if x0 is an odd number, but it's
+ * unlikely anyone will notice.. */
+ p += (y * stride) + ((x0 / 2) * 3) + 1;
+ for (x = x0; x < x1; x += 2) {
+ tmp = *p + shading_val;
+ *p++ = CLAMP (tmp, 0, 255);
+ tmp = *p + shading_val;
+ *p++ = CLAMP (tmp, 0, 255);
+ /* skip chroma */
+ p++;
+ }
+ }
+}
+
#define ARGB_SHADE_FUNCTION(name, OFFSET) \
static inline void \
gst_base_text_overlay_shade_##name (GstBaseTextOverlay * overlay, GstVideoFrame * dest, \
\
dest_ptr = dest->data[0];\
\
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);\
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);\
- \
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);\
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);\
- \
for (i = y0; i < y1; i++) {\
for (j = x0; j < x1; j++) {\
gint y, y_pos, k;\
overlay->need_render = FALSE;
}
+/* FIXME: should probably be relative to width/height (adjusted for PAR) */
+#define BOX_XPAD 6
+#define BOX_YPAD 6
+
+static void
+gst_base_text_overlay_shade_background (GstBaseTextOverlay * overlay,
+ GstVideoFrame * frame, gint x0, gint x1, gint y0, gint y1)
+{
+ x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
+ x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
+
+ y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
+ y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
+
+ switch (overlay->format) {
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ case GST_VIDEO_FORMAT_NV12:
+ case GST_VIDEO_FORMAT_NV21:
+ case GST_VIDEO_FORMAT_Y41B:
+ case GST_VIDEO_FORMAT_Y42B:
+ case GST_VIDEO_FORMAT_Y444:
+ case GST_VIDEO_FORMAT_YUV9:
+ case GST_VIDEO_FORMAT_YVU9:
+ case GST_VIDEO_FORMAT_GRAY8:
+ case GST_VIDEO_FORMAT_A420:
+ gst_base_text_overlay_shade_planar_Y (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ case GST_VIDEO_FORMAT_UYVY:
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_v308:
+ gst_base_text_overlay_shade_packed_Y (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_xRGB:
+ gst_base_text_overlay_shade_xRGB (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_xBGR:
+ gst_base_text_overlay_shade_xBGR (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_BGRx:
+ gst_base_text_overlay_shade_BGRx (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_RGBx:
+ gst_base_text_overlay_shade_RGBx (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_ARGB:
+ gst_base_text_overlay_shade_ARGB (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_ABGR:
+ gst_base_text_overlay_shade_ABGR (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_RGBA:
+ gst_base_text_overlay_shade_RGBA (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_BGRA:
+ gst_base_text_overlay_shade_BGRA (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_BGR:
+ case GST_VIDEO_FORMAT_RGB:
+ gst_base_text_overlay_shade_rgb24 (overlay, frame, x0, x1, y0, y1);
+ break;
+ case GST_VIDEO_FORMAT_IYU1:
+ gst_base_text_overlay_shade_IYU1 (overlay, frame, x0, x1, y0, y1);
+ break;
+ default:
+ GST_FIXME_OBJECT (overlay, "implement background shading for format %s",
+ gst_video_format_to_string (GST_VIDEO_FRAME_FORMAT (frame)));
+ break;
+ }
+}
+
static GstFlowReturn
gst_base_text_overlay_push_frame (GstBaseTextOverlay * overlay,
GstBuffer * video_frame)
{
- gint xpos, ypos;
GstVideoFrame frame;
if (overlay->composition == NULL)
goto done;
+ if (gst_pad_check_reconfigure (overlay->srcpad))
+ gst_base_text_overlay_negotiate (overlay);
+
video_frame = gst_buffer_make_writable (video_frame);
if (overlay->attach_compo_to_buffer) {
GST_MAP_READWRITE))
goto invalid_frame;
- gst_base_text_overlay_get_pos (overlay, &xpos, &ypos);
-
/* shaded background box */
if (overlay->want_shading) {
- switch (overlay->format) {
- case GST_VIDEO_FORMAT_I420:
- case GST_VIDEO_FORMAT_NV12:
- case GST_VIDEO_FORMAT_NV21:
- gst_base_text_overlay_shade_planar_Y (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_AYUV:
- case GST_VIDEO_FORMAT_UYVY:
- gst_base_text_overlay_shade_packed_Y (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_xRGB:
- gst_base_text_overlay_shade_xRGB (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_xBGR:
- gst_base_text_overlay_shade_xBGR (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_BGRx:
- gst_base_text_overlay_shade_BGRx (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_RGBx:
- gst_base_text_overlay_shade_RGBx (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_ARGB:
- gst_base_text_overlay_shade_ARGB (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_ABGR:
- gst_base_text_overlay_shade_ABGR (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_RGBA:
- gst_base_text_overlay_shade_RGBA (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_BGRA:
- gst_base_text_overlay_shade_BGRA (overlay, &frame,
- xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- default:
- g_assert_not_reached ();
- }
+ gint xpos, ypos;
+
+ gst_base_text_overlay_get_pos (overlay, &xpos, &ypos);
+
+ gst_base_text_overlay_shade_background (overlay, &frame,
+ xpos, xpos + overlay->image_width, ypos, ypos + overlay->image_height);
}
gst_video_overlay_composition_blend (overlay->composition, &frame);
}
static GstPadLinkReturn
-gst_base_text_overlay_text_pad_link (GstPad * pad, GstPad * peer)
+gst_base_text_overlay_text_pad_link (GstPad * pad, GstObject * parent,
+ GstPad * peer)
{
GstBaseTextOverlay *overlay;
- overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+ overlay = GST_BASE_TEXT_OVERLAY (parent);
if (G_UNLIKELY (!overlay))
return GST_PAD_LINK_REFUSED;
overlay->text_linked = TRUE;
- gst_object_unref (overlay);
-
return GST_PAD_LINK_OK;
}
static void
-gst_base_text_overlay_text_pad_unlink (GstPad * pad)
+gst_base_text_overlay_text_pad_unlink (GstPad * pad, GstObject * parent)
{
GstBaseTextOverlay *overlay;
/* don't use gst_pad_get_parent() here, will deadlock */
- overlay = GST_BASE_TEXT_OVERLAY (GST_PAD_PARENT (pad));
+ overlay = GST_BASE_TEXT_OVERLAY (parent);
GST_DEBUG_OBJECT (overlay, "Text pad unlinked");
GST_BASE_TEXT_OVERLAY_UNLOCK (overlay);
break;
}
+ case GST_EVENT_GAP:
+ {
+ GstClockTime start, duration;
+
+ gst_event_parse_gap (event, &start, &duration);
+ if (GST_CLOCK_TIME_IS_VALID (duration))
+ start += duration;
+ /* we do not expect another buffer until after gap,
+ * so that is our position now */
+ overlay->text_segment.position = start;
+
+ /* wake up the video chain, it might be waiting for a text buffer or
+ * a text segment update */
+ GST_BASE_TEXT_OVERLAY_LOCK (overlay);
+ GST_BASE_TEXT_OVERLAY_BROADCAST (overlay);
+ GST_BASE_TEXT_OVERLAY_UNLOCK (overlay);
+ break;
+ }
case GST_EVENT_FLUSH_STOP:
GST_BASE_TEXT_OVERLAY_LOCK (overlay);
GST_INFO_OBJECT (overlay, "text flush stop");
in_text = (gchar *) map.data;
in_size = map.size;
- /* g_markup_escape_text() absolutely requires valid UTF8 input, it
- * might crash otherwise. We don't fall back on GST_SUBTITLE_ENCODING
- * here on purpose, this is something that needs fixing upstream */
- if (!g_utf8_validate (in_text, in_size, NULL)) {
- const gchar *end = NULL;
-
- GST_WARNING_OBJECT (overlay, "received invalid UTF-8");
- in_text = g_strndup (in_text, in_size);
- while (!g_utf8_validate (in_text, in_size, &end) && end)
- *((gchar *) end) = '*';
- }
-
- /* Get the string */
- if (overlay->have_pango_markup) {
- text = g_strndup (in_text, in_size);
- } else {
- text = g_markup_escape_text (in_text, in_size);
- }
+ if (in_size > 0) {
+ /* g_markup_escape_text() absolutely requires valid UTF8 input, it
+ * might crash otherwise. We don't fall back on GST_SUBTITLE_ENCODING
+ * here on purpose, this is something that needs fixing upstream */
+ if (!g_utf8_validate (in_text, in_size, NULL)) {
+ const gchar *end = NULL;
+
+ GST_WARNING_OBJECT (overlay, "received invalid UTF-8");
+ in_text = g_strndup (in_text, in_size);
+ while (!g_utf8_validate (in_text, in_size, &end) && end)
+ *((gchar *) end) = '*';
+ }
- if (text != NULL && *text != '\0') {
- gint text_len = strlen (text);
+ /* Get the string */
+ if (overlay->have_pango_markup) {
+ text = g_strndup (in_text, in_size);
+ } else {
+ text = g_markup_escape_text (in_text, in_size);
+ }
- while (text_len > 0 && (text[text_len - 1] == '\n' ||
- text[text_len - 1] == '\r')) {
- --text_len;
+ if (text != NULL && *text != '\0') {
+ gint text_len = strlen (text);
+
+ while (text_len > 0 && (text[text_len - 1] == '\n' ||
+ text[text_len - 1] == '\r')) {
+ --text_len;
+ }
+ GST_DEBUG_OBJECT (overlay, "Rendering text '%*s'", text_len, text);
+ gst_base_text_overlay_render_text (overlay, text, text_len);
+ } else {
+ GST_DEBUG_OBJECT (overlay, "No text to render (empty buffer)");
+ gst_base_text_overlay_render_text (overlay, " ", 1);
}
- GST_DEBUG_OBJECT (overlay, "Rendering text '%*s'", text_len, text);
- gst_base_text_overlay_render_text (overlay, text, text_len);
+ if (in_text != (gchar *) map.data)
+ g_free (in_text);
} else {
GST_DEBUG_OBJECT (overlay, "No text to render (empty buffer)");
gst_base_text_overlay_render_text (overlay, " ", 1);
}
- if (in_text != (gchar *) map.data)
- g_free (in_text);
gst_buffer_unmap (overlay->text_buffer, &map);