static GstFlowReturn gst_rsvg_overlay_data_sink_chain (GstPad * pad, GstBuffer * buffer) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (GST_PAD_PARENT (pad)); gst_adapter_push (overlay->adapter, buffer); return GST_FLOW_OK; }
static void gst_rsvg_overlay_finalize (GObject * object) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (object); g_object_unref (overlay->adapter); G_OBJECT_CLASS (parent_class)->finalize (object); }
static gboolean gst_rsvg_overlay_set_caps (GstBaseTransform * btrans, GstCaps * incaps, GstCaps * outcaps) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (btrans); return G_LIKELY (gst_video_format_parse_caps (incaps, &overlay->caps_format, &overlay->caps_width, &overlay->caps_height)); }
static gboolean gst_rsvg_overlay_stop (GstBaseTransform * btrans) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (btrans); if (overlay->handle) { g_object_unref (overlay->handle); g_object_unref (overlay->adapter); overlay->handle = NULL; } return TRUE; }
static void gst_rsvg_overlay_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (object); switch (prop_id) { case PROP_X: g_value_set_int (value, overlay->x_offset); break; case PROP_Y: g_value_set_int (value, overlay->y_offset); break; case PROP_X_RELATIVE: g_value_set_float (value, overlay->x_relative); break; case PROP_Y_RELATIVE: g_value_set_float (value, overlay->y_relative); break; case PROP_WIDTH: g_value_set_int (value, overlay->width); break; case PROP_HEIGHT: g_value_set_int (value, overlay->height); break; case PROP_WIDTH_RELATIVE: g_value_set_float (value, overlay->width_relative); break; case PROP_HEIGHT_RELATIVE: g_value_set_float (value, overlay->height_relative); break; case PROP_FIT_TO_FRAME: g_value_set_boolean (value, (overlay->width_relative == 1.0 && overlay->height_relative == 1.0)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_rsvg_overlay_data_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (GST_PAD_PARENT (pad)); GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS:{ guint data_size; GST_RSVG_LOCK (overlay); /* FIXME: rsvgdec looks for </svg> in data to determine the end of SVG code. Should we really do the same here? IOW, could data be sent and _pushed() before the EOS gets processed? */ data_size = gst_adapter_available (overlay->adapter); if (data_size) { gst_rsvg_overlay_set_svg_data (overlay, (const gchar *) gst_adapter_take (overlay->adapter, data_size), FALSE); gst_adapter_clear (overlay->adapter); } GST_RSVG_UNLOCK (overlay); } break; case GST_EVENT_FLUSH_STOP: gst_adapter_clear (overlay->adapter); break; default: break; } /* Dropping all events here */ gst_event_unref (event); return TRUE; }
static GstFlowReturn gst_rsvg_overlay_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (btrans); cairo_surface_t *surface; cairo_t *cr; double applied_x_offset = (double) overlay->x_offset; double applied_y_offset = (double) overlay->y_offset; int applied_width = overlay->width; int applied_height = overlay->height; GST_RSVG_LOCK (overlay); if (!overlay->handle) { GST_RSVG_UNLOCK (overlay); return GST_FLOW_OK; } surface = cairo_image_surface_create_for_data (GST_BUFFER_DATA (buf), CAIRO_FORMAT_ARGB32, overlay->caps_width, overlay->caps_height, overlay->caps_width * 4); if (G_UNLIKELY (!surface)) return GST_FLOW_ERROR; cr = cairo_create (surface); if (G_UNLIKELY (!cr)) { cairo_surface_destroy (surface); return GST_FLOW_ERROR; } /* Compute relative dimensions if absolute dimensions are not set */ if (!applied_x_offset && overlay->x_relative) { applied_x_offset = overlay->x_relative * overlay->caps_width; } if (!applied_y_offset && overlay->y_relative) { applied_y_offset = overlay->y_relative * overlay->caps_height; } if (!applied_width && overlay->width_relative) { applied_width = (int) (overlay->width_relative * overlay->caps_width); } if (!applied_height && overlay->height_relative) { applied_height = (int) (overlay->height_relative * overlay->caps_height); } if (applied_x_offset || applied_y_offset) { cairo_translate (cr, applied_x_offset, applied_y_offset); } /* Scale when necessary, i.e. an absolute or relative dimension has been specified. */ if ((applied_width || applied_height) && overlay->svg_width && overlay->svg_height) { /* If may happen that only one of the dimension is specified. Use the original SVG size for the other dimension. */ if (!applied_width) applied_width = overlay->svg_width; if (!applied_height) applied_height = overlay->svg_height; cairo_scale (cr, (double) applied_width / overlay->svg_width, (double) applied_height / overlay->svg_height); } rsvg_handle_render_cairo (overlay->handle, cr); GST_RSVG_UNLOCK (overlay); cairo_destroy (cr); cairo_surface_destroy (surface); return GST_FLOW_OK; }
static void gst_rsvg_overlay_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (object); GST_RSVG_LOCK (overlay); switch (prop_id) { case PROP_DATA: { gst_rsvg_overlay_set_svg_data (overlay, g_value_get_string (value), FALSE); break; } case PROP_FILENAME: { gst_rsvg_overlay_set_svg_data (overlay, g_value_get_string (value), TRUE); break; } case PROP_FIT_TO_FRAME: { if (g_value_get_boolean (value)) { overlay->x_offset = 0; overlay->y_offset = 0; overlay->x_relative = 0.0; overlay->y_relative = 0.0; overlay->width = 0; overlay->height = 0; overlay->width_relative = 1.0; overlay->height_relative = 1.0; } else { overlay->width_relative = 0; overlay->height_relative = 0; } break; } case PROP_X: { overlay->x_offset = g_value_get_int (value); break; } case PROP_Y: { overlay->y_offset = g_value_get_int (value); break; } case PROP_X_RELATIVE: { overlay->x_relative = g_value_get_float (value); break; } case PROP_Y_RELATIVE: { overlay->y_relative = g_value_get_float (value); break; } case PROP_WIDTH: { overlay->width = g_value_get_int (value); break; } case PROP_HEIGHT: { overlay->height = g_value_get_int (value); break; } case PROP_WIDTH_RELATIVE: { overlay->width_relative = g_value_get_float (value); break; } case PROP_HEIGHT_RELATIVE: { overlay->height_relative = g_value_get_float (value); break; } default: { G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } GST_RSVG_UNLOCK (overlay); }
static GstFlowReturn gst_rsvg_overlay_transform_frame_ip (GstVideoFilter * vfilter, GstVideoFrame * frame) { GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (vfilter); cairo_surface_t *surface; cairo_t *cr; double applied_x_offset = (double) overlay->x_offset; double applied_y_offset = (double) overlay->y_offset; int applied_width = overlay->width; int applied_height = overlay->height; GST_RSVG_LOCK (overlay); if (!overlay->handle) { GST_RSVG_UNLOCK (overlay); return GST_FLOW_OK; } surface = cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (frame, 0), CAIRO_FORMAT_ARGB32, GST_VIDEO_FRAME_WIDTH (frame), GST_VIDEO_FRAME_HEIGHT (frame), GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0)); if (G_UNLIKELY (!surface)) return GST_FLOW_ERROR; cr = cairo_create (surface); if (G_UNLIKELY (!cr)) { cairo_surface_destroy (surface); return GST_FLOW_ERROR; } /* Compute relative dimensions if absolute dimensions are not set */ if (!applied_x_offset && overlay->x_relative) { applied_x_offset = overlay->x_relative * GST_VIDEO_FRAME_WIDTH (frame); } if (!applied_y_offset && overlay->y_relative) { applied_y_offset = overlay->y_relative * GST_VIDEO_FRAME_HEIGHT (frame); } if (!applied_width && overlay->width_relative) { applied_width = (int) (overlay->width_relative * GST_VIDEO_FRAME_WIDTH (frame)); } if (!applied_height && overlay->height_relative) { applied_height = (int) (overlay->height_relative * GST_VIDEO_FRAME_HEIGHT (frame)); } if (applied_x_offset || applied_y_offset) { cairo_translate (cr, applied_x_offset, applied_y_offset); } /* Scale when necessary, i.e. an absolute or relative dimension has been specified. */ if ((applied_width || applied_height) && overlay->svg_width && overlay->svg_height) { /* If may happen that only one of the dimension is specified. Use the original SVG size for the other dimension. */ if (!applied_width) applied_width = overlay->svg_width; if (!applied_height) applied_height = overlay->svg_height; cairo_scale (cr, (double) applied_width / overlay->svg_width, (double) applied_height / overlay->svg_height); } rsvg_handle_render_cairo (overlay->handle, cr); GST_RSVG_UNLOCK (overlay); cairo_destroy (cr); cairo_surface_destroy (surface); return GST_FLOW_OK; }