"GdkPixbuf image decoder",
"Codec/Decoder/Image",
"Decodes images in a video stream using GdkPixbuf",
- "David A. Schleef <ds@schleef.org>",
+ "David A. Schleef <ds@schleef.org>, Renato Filho <renato.filho@indt.org.br>",
};
/* Filter signals and args */
ARG_SILENT
};
+
+
static GstStaticPadTemplate gst_gdk_pixbuf_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
static void gst_gdk_pixbuf_base_init (gpointer g_class);
static void gst_gdk_pixbuf_class_init (GstGdkPixbufClass * klass);
-static void gst_gdk_pixbuf_init (GstGdkPixbuf * filter);
+static void gst_gdk_pixbuf_init (GstGdkPixbuf * filter,
+ GstGdkPixbufClass * klass);
static void gst_gdk_pixbuf_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gdk_pixbuf_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static void gst_gdk_pixbuf_chain (GstPad * pad, GstData * _data);
+static GstFlowReturn gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_gdk_pixbuf_event (GstPad * pad, GstEvent * event);
#ifdef enable_typefind
static void gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore);
#endif
-static GstElementClass *parent_class = NULL;
-static GstPadLinkReturn
-gst_gdk_pixbuf_sink_link (GstPad * pad, const GstCaps * caps)
+GST_BOILERPLATE (GstGdkPixbuf, gst_gdk_pixbuf, GstElement, GST_TYPE_ELEMENT)
+
+ static gboolean gst_gdk_pixbuf_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstGdkPixbuf *filter;
- const GValue *fps;
+ const GValue *framerate;
+ GstStructure *s;
filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
- g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
- g_return_val_if_fail (GST_IS_GDK_PIXBUF (filter), GST_PAD_LINK_REFUSED);
-
- fps = gst_structure_get_value (gst_caps_get_structure (caps, 0), "framerate");
- if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) {
- filter->fps_n = gst_value_get_fraction_numerator (fps);
- filter->fps_d = gst_value_get_fraction_denominator (fps);
- } else
- return GST_PAD_LINK_REFUSED;
+ s = gst_caps_get_structure (caps, 0);
+
+ filter->framerate_numerator = 0;
+ filter->framerate_denominator = 1;
+ if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
+ filter->framerate_numerator = gst_value_get_fraction_numerator (framerate);
+ filter->framerate_denominator =
+ gst_value_get_fraction_denominator (framerate);
+ GST_DEBUG ("got framerate of %d/%d fps => packetized mode",
+ filter->framerate_numerator, filter->framerate_denominator);
+ }
- return GST_PAD_LINK_OK;
+ return TRUE;
}
+
#if GDK_PIXBUF_MAJOR == 2 && GDK_PIXBUF_MINOR < 2
/* gdk-pixbuf prior to 2.2 didn't have gdk_pixbuf_get_formats().
* These are just the formats that gdk-pixbuf is known to support.
* But maybe not -- it may have been compiled without an external
* library. */
+
static GstCaps *
gst_gdk_pixbuf_get_capslist (void)
{
return_caps = gst_caps_intersect (capslist,
gst_static_caps_get (&gst_gdk_pixbuf_sink_template.static_caps));
- gst_caps_free (capslist);
+ gst_caps_unref (capslist);
return return_caps;
}
#endif
return gst_gdk_pixbuf_get_capslist ();
}
-GType
-gst_gdk_pixbuf_get_type (void)
-{
- static GType plugin_type = 0;
-
- if (!plugin_type) {
- static const GTypeInfo plugin_info = {
- sizeof (GstGdkPixbufClass),
- gst_gdk_pixbuf_base_init,
- NULL,
- (GClassInitFunc) gst_gdk_pixbuf_class_init,
- NULL,
- NULL,
- sizeof (GstGdkPixbuf),
- 0,
- (GInstanceInitFunc) gst_gdk_pixbuf_init,
- };
-
- plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
- "GstGdkPixbuf", &plugin_info, 0);
- }
- return plugin_type;
-}
-
static void
gst_gdk_pixbuf_base_init (gpointer g_class)
{
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ gobject_class->set_property = gst_gdk_pixbuf_set_property;
+ gobject_class->get_property = gst_gdk_pixbuf_get_property;
+
+
g_object_class_install_property (gobject_class, ARG_SILENT,
g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
FALSE, G_PARAM_READWRITE));
- gobject_class->set_property = gst_gdk_pixbuf_set_property;
- gobject_class->get_property = gst_gdk_pixbuf_get_property;
}
static void
-gst_gdk_pixbuf_init (GstGdkPixbuf * filter)
+gst_gdk_pixbuf_init (GstGdkPixbuf * filter, GstGdkPixbufClass * klass)
{
filter->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_gdk_pixbuf_sink_template), "sink");
- gst_pad_set_link_function (filter->sinkpad, gst_gdk_pixbuf_sink_link);
+ gst_pad_set_setcaps_function (filter->sinkpad, gst_gdk_pixbuf_sink_setcaps);
gst_pad_set_getcaps_function (filter->sinkpad, gst_gdk_pixbuf_sink_getcaps);
- filter->srcpad =
- gst_pad_new_from_template (gst_static_pad_template_get
- (&gst_gdk_pixbuf_src_template), "src");
- gst_pad_use_explicit_caps (filter->srcpad);
+ gst_pad_set_chain_function (filter->sinkpad,
+ (GstPadChainFunction) gst_gdk_pixbuf_chain);
+
+ gst_pad_set_event_function (filter->sinkpad, gst_gdk_pixbuf_event);
+
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
+
+
+ filter->srcpad = gst_pad_new_from_template (gst_static_pad_template_get
+ (&gst_gdk_pixbuf_src_template), "src");
+
+ gst_pad_use_fixed_caps (filter->srcpad);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
- gst_pad_set_chain_function (filter->sinkpad, gst_gdk_pixbuf_chain);
- GST_OBJECT_FLAG_SET (GST_ELEMENT (filter), GST_ELEMENT_EVENT_AWARE);
+ filter->last_timestamp = GST_CLOCK_TIME_NONE;
+ filter->pixbuf_loader = NULL;
}
-static void
-gst_gdk_pixbuf_chain (GstPad * pad, GstData * _data)
+static GstFlowReturn
+gst_gdk_pixbuf_flush (GstGdkPixbuf * filter)
{
- GstBuffer *buf = GST_BUFFER (_data);
- GstGdkPixbuf *filter;
- GError *error = NULL;
- gboolean push_buffer = FALSE;
- gboolean dump_buffer = FALSE;
- gboolean got_eos = FALSE;
-
- GST_DEBUG ("gst_gdk_pixbuf_chain");
+ GstBuffer *outbuf;
+ GdkPixbuf *pixbuf;
+ int y;
+ guint8 *out_pix;
+ guint8 *in_pix;
+ int in_rowstride;
+ GstFlowReturn ret;
+ GstCaps *caps = NULL;
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader);
+ if (pixbuf == NULL) {
+ GST_DEBUG ("error geting pixbuf");
+ return GST_FLOW_ERROR;
+ }
- g_return_if_fail (GST_IS_PAD (pad));
- g_return_if_fail (buf != NULL);
-
- filter = GST_GDK_PIXBUF (GST_OBJECT_PARENT (pad));
- g_return_if_fail (GST_IS_GDK_PIXBUF (filter));
-
- if (GST_IS_EVENT (_data)) {
- GstEvent *event = GST_EVENT (buf);
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- push_buffer = TRUE;
- got_eos = TRUE;
- break;
- case GST_EVENT_DISCONTINUOUS:
- dump_buffer = TRUE;
- break;
- default:
- gst_pad_event_default (pad, event);
- return;
+ if (filter->image_size == 0) {
+ filter->width = gdk_pixbuf_get_width (pixbuf);
+ filter->height = gdk_pixbuf_get_height (pixbuf);
+ filter->rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ filter->image_size = filter->rowstride * filter->height;
+
+ if (gdk_pixbuf_get_rowstride (pixbuf) / filter->width == 4) {
+ caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBA);
+ } else if (gdk_pixbuf_get_rowstride (pixbuf) / filter->width == 3) {
+ caps = gst_caps_from_string (GST_VIDEO_CAPS_RGB);
+ } else {
+ GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL),
+ ("Bpp %d not supported", gdk_pixbuf_get_bits_per_sample (pixbuf)));
+ return GST_FLOW_ERROR;
}
+ gst_caps_set_simple (caps,
+ "width", G_TYPE_INT, filter->width,
+ "height", G_TYPE_INT, filter->height,
+ "framerate", GST_TYPE_FRACTION, filter->framerate_numerator,
+ filter->framerate_denominator, NULL);
+
+ GST_DEBUG ("Set size to %dx%d", filter->width, filter->height);
+ gst_pad_set_caps (filter->srcpad, caps);
+ gst_caps_unref (caps);
}
- if (filter->last_timestamp != GST_BUFFER_TIMESTAMP (buf)) {
- push_buffer = TRUE;
+ ret = gst_pad_alloc_buffer_and_set_caps (filter->srcpad,
+ GST_BUFFER_OFFSET_NONE,
+ filter->image_size, GST_PAD_CAPS (filter->srcpad), &outbuf);
+
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG ("Failed to create outbuffer - %d", ret);
+ return GST_FLOW_ERROR;
}
- if (push_buffer) {
- if (filter->pixbuf_loader != NULL) {
- GstBuffer *outbuf;
- GdkPixbuf *pixbuf;
- GError *error = NULL;
+ gst_caps_unref (caps);
+ caps = gst_pad_get_negotiated_caps (filter->srcpad);
+ GST_DEBUG ("Caps negotiated %s", gst_caps_to_string (caps));
+ gst_caps_unref (caps);
- if (!gdk_pixbuf_loader_close (filter->pixbuf_loader, &error)) {
- GST_ELEMENT_ERROR (filter, LIBRARY, SHUTDOWN, (NULL), (error->message));
- g_error_free (error);
- return;
- }
+ GST_BUFFER_TIMESTAMP (outbuf) = filter->last_timestamp;
+ GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
- pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader);
+ in_pix = gdk_pixbuf_get_pixels (pixbuf);
+ in_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ out_pix = GST_BUFFER_DATA (outbuf);
- if (filter->image_size == 0) {
- GstCaps *caps;
+ for (y = 0; y < filter->height; y++) {
+ memcpy (out_pix, in_pix, filter->rowstride);
+ in_pix += in_rowstride;
+ out_pix += filter->rowstride;
+ }
- filter->width = gdk_pixbuf_get_width (pixbuf);
- filter->height = gdk_pixbuf_get_height (pixbuf);
- /* gdk_pixbuf likes to pad rowstride to 4 byte boundaries which we can't do
- * at the moment
- */
- filter->rowstride = filter->width * 3;
- filter->image_size = filter->rowstride * filter->height;
+ GST_DEBUG ("pushing... %d bytes", GST_BUFFER_SIZE (outbuf));
+ return gst_pad_push (filter->srcpad, outbuf);
+}
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (filter->srcpad));
- gst_caps_set_simple (caps,
- "width", G_TYPE_INT, filter->width,
- "height", G_TYPE_INT, filter->height,
- "framerate", G_TYPE_DOUBLE, filter->framerate, NULL);
+static gboolean
+gst_gdk_pixbuf_event (GstPad * pad, GstEvent * event)
+{
+ GstFlowReturn res = GST_FLOW_OK;
+ gboolean ret = TRUE;
+ GstGdkPixbuf *pixbuf;
- gst_pad_set_explicit_caps (filter->srcpad, caps);
- }
+ pixbuf = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
- outbuf =
- gst_pad_alloc_buffer_and_set_caps (filter->srcpad,
- GST_BUFFER_OFFSET_NONE, filter->image_size);
- GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
- GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
-
- {
- int y;
- guint8 *out_pix;
- guint8 *in_pix;
- int in_rowstride;
-
- in_pix = gdk_pixbuf_get_pixels (pixbuf);
- in_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- out_pix = GST_BUFFER_DATA (outbuf);
-
- for (y = 0; y < filter->height; y++) {
- memcpy (out_pix, in_pix, filter->rowstride);
- in_pix += in_rowstride;
- out_pix += filter->rowstride;
- }
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL);
+ res = gst_gdk_pixbuf_flush (pixbuf);
+ g_object_unref (G_OBJECT (pixbuf->pixbuf_loader));
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_FLUSH_STOP:
+ if (pixbuf->pixbuf_loader != NULL) {
+ gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL);
+ g_object_unref (G_OBJECT (pixbuf->pixbuf_loader));
+ pixbuf->pixbuf_loader = NULL;
}
-
- gst_pad_push (filter->srcpad, GST_DATA (outbuf));
-
- g_object_unref (G_OBJECT (filter->pixbuf_loader));
- filter->pixbuf_loader = NULL;
- dump_buffer = FALSE;
- }
+ break;
+ default:
+ break;
}
- if (dump_buffer) {
- if (filter->pixbuf_loader != NULL) {
- gdk_pixbuf_loader_close (filter->pixbuf_loader, NULL);
- g_object_unref (G_OBJECT (filter->pixbuf_loader));
- filter->pixbuf_loader = NULL;
- }
+ if (res == GST_FLOW_OK) {
+ ret = gst_pad_event_default (pad, event);
+ } else {
+ ret = FALSE;
}
- if (GST_IS_BUFFER (_data)) {
- if (filter->pixbuf_loader == NULL) {
- filter->pixbuf_loader = gdk_pixbuf_loader_new ();
- filter->last_timestamp = GST_BUFFER_TIMESTAMP (buf);
- }
+ gst_object_unref (pixbuf);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstGdkPixbuf *filter;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GError *error = NULL;
+ GstClockTime timestamp;
- gdk_pixbuf_loader_write (filter->pixbuf_loader, GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf), &error);
- gst_buffer_unref (buf);
+ GST_DEBUG ("gst_gdk_pixbuf_chain");
+ filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+ filter->last_timestamp = timestamp;
}
- if (got_eos) {
- gst_pad_event_default (pad, GST_EVENT (_data));
+ if (filter->pixbuf_loader == NULL) {
+ filter->pixbuf_loader = gdk_pixbuf_loader_new ();
}
+
+ GST_DEBUG ("Writing buffer size %d", GST_BUFFER_SIZE (buf));
+ if (gdk_pixbuf_loader_write (filter->pixbuf_loader, GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf), &error) == FALSE) {
+ GST_DEBUG ("gst_gdk_pixbuf_chain ERROR: %s", error->message);
+ ret = GST_FLOW_ERROR;
+ goto need_more_data;
+ }
+
+need_more_data:
+ gst_object_unref (filter);
+ return ret;
}
static void
switch (prop_id) {
case ARG_SILENT:
- //filter->silent = g_value_get_boolean (value);
+ /* filter->silent = g_value_get_boolean (value); */
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
switch (prop_id) {
case ARG_SILENT:
- //g_value_set_boolean (value, filter->silent);
+ /* g_value_set_boolean (value, filter->silent); */
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
return TRUE;
}
+
/* this is the structure that gst-register looks for
* so keep the name plugin_desc, or you cannot get your plug-in registered */
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gdkpixbuf",
- "GDK Pixbuf decoder & scaler", plugin_init, VERSION, "LGPL",
- GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
+ "GDK Pixbuf decoder & scaler",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
#define GST_RGB24_SIZE(width,height) ((height)*GST_RGB24_ROWSTRIDE(width))
-/* debug variable definition */
GST_DEBUG_CATEGORY (pixbufscale_debug);
#define GST_CAT_DEFAULT pixbufscale_debug
GST_ELEMENT_DETAILS ("Gdk Pixbuf scaler",
"Filter/Effect/Video",
"Resizes video",
- "Jan Schmidt <thaytan@mad.scientist.com>\nWim Taymans <wim.taymans@chello.be>");
+ "Jan Schmidt <thaytan@mad.scientist.com>\n"
+ "Wim Taymans <wim.taymans@chello.be>\n"
+ "Renato Filho <renato.filho@indt.org.br>");
/* GstPixbufScale signals and args */
enum
{
static GType pixbufscale_method_type = 0;
static GEnumValue pixbufscale_methods[] = {
- {GST_PIXBUFSCALE_NEAREST, "Nearest Neighbour", "nearest"},
- {GST_PIXBUFSCALE_TILES, "Tiles", "tiles"},
- {GST_PIXBUFSCALE_BILINEAR, "Bilinear", "bilinear"},
- {GST_PIXBUFSCALE_HYPER, "Hyper", "hyper"},
+ {GST_PIXBUFSCALE_NEAREST, "0", "Nearest Neighbour"},
+ {GST_PIXBUFSCALE_TILES, "1", "Tiles"},
+ {GST_PIXBUFSCALE_BILINEAR, "2", "Bilinear"},
+ {GST_PIXBUFSCALE_HYPER, "3", "Hyper"},
{0, NULL, NULL},
};
static void gst_pixbufscale_base_init (gpointer g_class);
static void gst_pixbufscale_class_init (GstPixbufScaleClass * klass);
-static void gst_pixbufscale_init (GstPixbufScale * pixbufscale);
-static gboolean gst_pixbufscale_handle_src_event (GstPad * pad,
- GstEvent * event);
-
+static void gst_pixbufscale_init (GstPixbufScale * pixbufscale,
+ GstPixbufScaleClass * kclass);
static void gst_pixbufscale_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_pixbufscale_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static void gst_pixbufscale_chain (GstPad * pad, GstData * _data);
+static GstCaps *gst_pixbufscale_transform_caps (GstBaseTransform * trans,
+ GstPadDirection direction, GstCaps * caps);
+static gboolean gst_pixbufscale_set_caps (GstBaseTransform * trans,
+ GstCaps * in, GstCaps * out);
+static gboolean gst_pixbufscale_get_unit_size (GstBaseTransform * trans,
+ GstCaps * caps, guint * size);
+static void gst_pixbufscale_fixate_caps (GstBaseTransform * base,
+ GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
+static GstFlowReturn gst_pixbufscale_transform (GstBaseTransform * trans,
+ GstBuffer * in, GstBuffer * out);
+static gboolean gst_pixbufscale_handle_src_event (GstPad * pad,
+ GstEvent * event);
-static GstElementClass *parent_class = NULL;
-GType
-gst_pixbufscale_get_type (void)
-{
- static GType pixbufscale_type = 0;
-
- if (!pixbufscale_type) {
- static const GTypeInfo pixbufscale_info = {
- sizeof (GstPixbufScaleClass),
- gst_pixbufscale_base_init,
- NULL,
- (GClassInitFunc) gst_pixbufscale_class_init,
- NULL,
- NULL,
- sizeof (GstPixbufScale),
- 0,
- (GInstanceInitFunc) gst_pixbufscale_init,
- };
-
- pixbufscale_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstPixbufScale",
- &pixbufscale_info, 0);
- }
- return pixbufscale_type;
-}
+static gboolean parse_caps (GstCaps * caps, gint * width, gint * height);
-static void
-gst_pixbufscale_base_init (gpointer g_class)
+GST_BOILERPLATE (GstPixbufScale, gst_pixbufscale, GstBaseTransform,
+ GST_TYPE_BASE_TRANSFORM)
+
+ static void gst_pixbufscale_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_pixbufscale_class_init (GstPixbufScaleClass * klass)
{
GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
+ GstBaseTransformClass *trans_class;
gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
+ trans_class = (GstBaseTransformClass *) klass;
+
+ gobject_class->set_property = gst_pixbufscale_set_property;
+ gobject_class->get_property = gst_pixbufscale_get_property;
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD,
+ g_object_class_install_property (gobject_class,
+ ARG_METHOD,
g_param_spec_enum ("method", "method", "method",
GST_TYPE_PIXBUFSCALE_METHOD, GST_PIXBUFSCALE_BILINEAR,
G_PARAM_READWRITE));
- parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ trans_class->transform_caps =
+ GST_DEBUG_FUNCPTR (gst_pixbufscale_transform_caps);
+ trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_set_caps);
+ trans_class->get_unit_size =
+ GST_DEBUG_FUNCPTR (gst_pixbufscale_get_unit_size);
+ trans_class->transform = GST_DEBUG_FUNCPTR (gst_pixbufscale_transform);
+ trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_fixate_caps);
+ trans_class->passthrough_on_same_caps = TRUE;
- gobject_class->set_property = gst_pixbufscale_set_property;
- gobject_class->get_property = gst_pixbufscale_get_property;
+ parent_class = g_type_class_peek_parent (klass);
}
+static void
+gst_pixbufscale_init (GstPixbufScale * pixbufscale,
+ GstPixbufScaleClass * kclass)
+{
+ GST_DEBUG_OBJECT (pixbufscale, "_init");
+ GstBaseTransform *trans = GST_BASE_TRANSFORM (pixbufscale);
+
+ gst_pad_set_event_function (trans->srcpad, gst_pixbufscale_handle_src_event);
+
+ pixbufscale->method = GST_PIXBUFSCALE_TILES;
+ pixbufscale->gdk_method = GDK_INTERP_TILES;
+}
+
+static void
+gst_pixbufscale_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstPixbufScale *src;
+
+ g_return_if_fail (GST_IS_PIXBUFSCALE (object));
+ src = GST_PIXBUFSCALE (object);
+
+ switch (prop_id) {
+ case ARG_METHOD:
+ src->method = g_value_get_enum (value);
+ switch (src->method) {
+ case GST_PIXBUFSCALE_NEAREST:
+ src->gdk_method = GDK_INTERP_NEAREST;
+ break;
+ case GST_PIXBUFSCALE_TILES:
+ src->gdk_method = GDK_INTERP_TILES;
+ break;
+ case GST_PIXBUFSCALE_BILINEAR:
+ src->gdk_method = GDK_INTERP_BILINEAR;
+ break;
+ case GST_PIXBUFSCALE_HYPER:
+ src->gdk_method = GDK_INTERP_HYPER;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstPixbufScale *src;
+
+ g_return_if_fail (GST_IS_PIXBUFSCALE (object));
+ src = GST_PIXBUFSCALE (object);
+
+ switch (prop_id) {
+ case ARG_METHOD:
+ g_value_set_enum (value, src->method);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
static GstCaps *
-gst_pixbufscale_getcaps (GstPad * pad)
+gst_pixbufscale_transform_caps (GstBaseTransform * trans,
+ GstPadDirection direction, GstCaps * caps)
{
GstPixbufScale *pixbufscale;
- GstCaps *othercaps;
- GstCaps *caps;
- GstPad *otherpad;
+ GstCaps *ret;
int i;
- pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
-
- otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad :
- pixbufscale->srcpad;
- othercaps = gst_pad_get_allowed_caps (otherpad);
+ pixbufscale = GST_PIXBUFSCALE (trans);
+ ret = gst_caps_copy (caps);
- caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
- gst_caps_free (othercaps);
-
- for (i = 0; i < gst_caps_get_size (caps); i++) {
- GstStructure *structure = gst_caps_get_structure (caps, i);
+ for (i = 0; i < gst_caps_get_size (ret); i++) {
+ GstStructure *structure = gst_caps_get_structure (ret, i);
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, 16, 4096,
gst_structure_remove_field (structure, "pixel-aspect-ratio");
}
- GST_DEBUG ("getcaps are: %" GST_PTR_FORMAT, caps);
- return caps;
+ GST_DEBUG_OBJECT (trans, "returning caps: %", ret);
+ return ret;
}
-static GstPadLinkReturn
-gst_pixbufscale_link (GstPad * pad, const GstCaps * caps)
+static gboolean
+parse_caps (GstCaps * caps, gint * width, gint * height)
{
- GstPixbufScale *pixbufscale;
- GstPadLinkReturn ret;
- GstPad *otherpad;
+ gboolean ret;
GstStructure *structure;
- int height, width;
- gchar *caps_string;
- caps_string = gst_caps_to_string (caps);
- GST_DEBUG ("gst_pixbufscale_link %s\n", caps_string);
- g_free (caps_string);
+ structure = gst_caps_get_structure (caps, 0);
+ ret = gst_structure_get_int (structure, "width", width);
+ ret &= gst_structure_get_int (structure, "height", height);
- pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
+ return ret;
+}
- otherpad = (pad == pixbufscale->srcpad) ? pixbufscale->sinkpad :
- pixbufscale->srcpad;
+static gboolean
+gst_pixbufscale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
+{
+ GstPixbufScale *pixbufscale;
+ gboolean ret;
- structure = gst_caps_get_structure (caps, 0);
- ret = gst_structure_get_int (structure, "width", &width);
- ret &= gst_structure_get_int (structure, "height", &height);
+ pixbufscale = GST_PIXBUFSCALE (trans);
+ ret = parse_caps (in, &pixbufscale->from_width, &pixbufscale->from_height);
+ ret &= parse_caps (out, &pixbufscale->to_width, &pixbufscale->to_height);
+ if (!ret)
+ goto done;
- ret = gst_pad_try_set_caps (otherpad, caps);
- if (ret == GST_PAD_LINK_OK) {
- /* cool, we can use passthru */
+ pixbufscale->from_stride = GST_ROUND_UP_4 (pixbufscale->from_width * 3);
+ pixbufscale->from_buf_size =
+ pixbufscale->from_stride * pixbufscale->from_height;
- pixbufscale->to_width = width;
- pixbufscale->to_height = height;
- pixbufscale->from_width = width;
- pixbufscale->from_height = height;
+ pixbufscale->to_stride = GST_ROUND_UP_4 (pixbufscale->to_width * 3);
+ pixbufscale->to_buf_size = pixbufscale->to_stride * pixbufscale->to_height;
- pixbufscale->from_buf_size = GST_RGB24_SIZE (width, height);
- pixbufscale->to_buf_size = GST_RGB24_SIZE (width, height);
- pixbufscale->from_stride = GST_RGB24_ROWSTRIDE (width);
- pixbufscale->to_stride = GST_RGB24_ROWSTRIDE (width);
+ GST_DEBUG_OBJECT (pixbufscale, "from=%dx%d, size %d -> to=%dx%d, size %d",
+ pixbufscale->from_width, pixbufscale->from_height,
+ pixbufscale->from_buf_size, pixbufscale->to_width, pixbufscale->to_height,
+ pixbufscale->to_buf_size);
- pixbufscale->inited = TRUE;
+done:
+ return ret;
+}
- return GST_PAD_LINK_OK;
- }
- if (gst_pad_is_negotiated (otherpad)) {
- GstCaps *newcaps = gst_caps_copy (caps);
+static gboolean
+gst_pixbufscale_get_unit_size (GstBaseTransform * trans,
+ GstCaps * caps, guint * size)
+{
+ GstPixbufScale *pixbufscale;
+ gint width, height;
- if (pad == pixbufscale->srcpad) {
- gst_caps_set_simple (newcaps,
- "width", G_TYPE_INT, pixbufscale->from_width,
- "height", G_TYPE_INT, pixbufscale->from_height, NULL);
- } else {
- gst_caps_set_simple (newcaps,
- "width", G_TYPE_INT, pixbufscale->to_width,
- "height", G_TYPE_INT, pixbufscale->to_height, NULL);
- }
- ret = gst_pad_try_set_caps (otherpad, newcaps);
- if (GST_PAD_LINK_FAILED (ret)) {
- return GST_PAD_LINK_REFUSED;
- }
- }
+ g_return_val_if_fail (size, FALSE);
- pixbufscale->passthru = FALSE;
+ pixbufscale = GST_PIXBUFSCALE (trans);
- if (pad == pixbufscale->srcpad) {
- pixbufscale->to_width = width;
- pixbufscale->to_height = height;
- } else {
- pixbufscale->from_width = width;
- pixbufscale->from_height = height;
- }
+ if (!parse_caps (caps, &width, &height))
+ return FALSE;
- if (gst_pad_is_negotiated (otherpad)) {
- pixbufscale->from_buf_size =
- GST_RGB24_SIZE (pixbufscale->from_width, pixbufscale->from_height);
- pixbufscale->to_buf_size =
- GST_RGB24_SIZE (pixbufscale->to_width, pixbufscale->to_height);
- pixbufscale->from_stride = GST_RGB24_ROWSTRIDE (pixbufscale->from_width);
- pixbufscale->to_stride = GST_RGB24_ROWSTRIDE (pixbufscale->to_width);
- pixbufscale->inited = TRUE;
- }
+ *size = GST_ROUND_UP_4 (width * 3) * height;
- return GST_PAD_LINK_OK;
+ return TRUE;
}
static void
-gst_pixbufscale_init (GstPixbufScale * pixbufscale)
+gst_pixbufscale_fixate_caps (GstBaseTransform * base, GstPadDirection direction,
+ GstCaps * caps, GstCaps * othercaps)
{
- GST_DEBUG_OBJECT (pixbufscale, "_init");
- pixbufscale->sinkpad =
- gst_pad_new_from_template (gst_static_pad_template_get
- (&gst_pixbufscale_sink_template), "sink");
- gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->sinkpad);
- gst_pad_set_chain_function (pixbufscale->sinkpad, gst_pixbufscale_chain);
- gst_pad_set_link_function (pixbufscale->sinkpad, gst_pixbufscale_link);
- gst_pad_set_getcaps_function (pixbufscale->sinkpad, gst_pixbufscale_getcaps);
-
- pixbufscale->srcpad =
- gst_pad_new_from_template (gst_static_pad_template_get
- (&gst_pixbufscale_src_template), "src");
- gst_element_add_pad (GST_ELEMENT (pixbufscale), pixbufscale->srcpad);
- gst_pad_set_event_function (pixbufscale->srcpad,
- gst_pixbufscale_handle_src_event);
- gst_pad_set_link_function (pixbufscale->srcpad, gst_pixbufscale_link);
- gst_pad_set_getcaps_function (pixbufscale->srcpad, gst_pixbufscale_getcaps);
-
- pixbufscale->inited = FALSE;
-
- pixbufscale->method = GST_PIXBUFSCALE_TILES;
- pixbufscale->gdk_method = GDK_INTERP_TILES;
-}
-
-static gboolean
-gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event)
-{
- GstPixbufScale *pixbufscale;
- double a;
- GstStructure *structure;
- GstEvent *new_event;
+ GstStructure *ins, *outs;
+ const GValue *from_par, *to_par;
+
+ g_return_if_fail (gst_caps_is_fixed (caps));
+
+ GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
+ " based on caps %" GST_PTR_FORMAT, othercaps, caps);
+
+ ins = gst_caps_get_structure (caps, 0);
+ outs = gst_caps_get_structure (othercaps, 0);
+
+ from_par = gst_structure_get_value (ins, "pixel-aspect-ratio");
+ to_par = gst_structure_get_value (outs, "pixel-aspect-ratio");
+
+ if (from_par && to_par) {
+ GValue to_ratio = { 0, }; /* w/h of output video */
+ int from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
+ int count = 0, w = 0, h = 0, num, den;
+
+ /* if both width and height are already fixed, we can't do anything
+ * * about it anymore */
+ if (gst_structure_get_int (outs, "width", &w))
+ ++count;
+ if (gst_structure_get_int (outs, "height", &h))
+ ++count;
+ if (count == 2) {
+ GST_DEBUG_OBJECT (base, "dimensions already set to %dx%d, not fixating",
+ w, h);
+ return;
+ }
- pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
+ gst_structure_get_int (ins, "width", &from_w);
+ gst_structure_get_int (ins, "height", &from_h);
+ from_par_n = gst_value_get_fraction_numerator (from_par);
+ from_par_d = gst_value_get_fraction_denominator (from_par);
+ to_par_n = gst_value_get_fraction_numerator (to_par);
+ to_par_d = gst_value_get_fraction_denominator (to_par);
+
+ g_value_init (&to_ratio, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&to_ratio, from_w * from_par_n * to_par_d,
+ from_h * from_par_d * to_par_n);
+ num = gst_value_get_fraction_numerator (&to_ratio);
+ den = gst_value_get_fraction_denominator (&to_ratio);
+ GST_DEBUG_OBJECT (base,
+ "scaling input with %dx%d and PAR %d/%d to output PAR %d/%d",
+ from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d);
+ GST_DEBUG_OBJECT (base,
+ "resulting output should respect ratio of %d/%d", num, den);
+
+ /* now find a width x height that respects this display ratio.
+ * * prefer those that have one of w/h the same as the incoming video
+ * * using wd / hd = num / den */
+
+ /* start with same height, because of interlaced video */
+ /* check hd / den is an integer scale factor, and scale wd with the PAR */
+ if (from_h % den == 0) {
+ GST_DEBUG_OBJECT (base, "keeping video height");
+ h = from_h;
+ w = h * num / den;
+ } else if (from_w % num == 0) {
+ GST_DEBUG_OBJECT (base, "keeping video width");
+ w = from_w;
+ h = w * den / num;
+ } else {
+ GST_DEBUG_OBJECT (base, "approximating but keeping video height");
+ h = from_h;
+ w = h * num / den;
+ }
+ GST_DEBUG_OBJECT (base, "scaling to %dx%d", w, h);
+ /* now fixate */
+ gst_structure_fixate_field_nearest_int (outs, "width", w);
+ gst_structure_fixate_field_nearest_int (outs, "height", h);
+ } else {
+ gint width, height;
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NAVIGATION:
- structure = gst_structure_copy (event->event_data.structure.structure);
- if (gst_structure_get_double (event->event_data.structure.structure,
- "pointer_x", &a)) {
- gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
- a * pixbufscale->from_width / pixbufscale->to_width, NULL);
+ if (gst_structure_get_int (ins, "width", &width)) {
+ if (gst_structure_has_field (outs, "width")) {
+ gst_structure_fixate_field_nearest_int (outs, "width", width);
}
- if (gst_structure_get_double (event->event_data.structure.structure,
- "pointer_y", &a)) {
- gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
- a * pixbufscale->from_height / pixbufscale->to_height, NULL);
+ }
+ if (gst_structure_get_int (ins, "height", &height)) {
+ if (gst_structure_has_field (outs, "height")) {
+ gst_structure_fixate_field_nearest_int (outs, "height", height);
}
- gst_event_unref (event);
- new_event = gst_event_new (GST_EVENT_NAVIGATION);
- new_event->event_data.structure.structure = structure;
- return gst_pad_event_default (pad, new_event);
- break;
- default:
- return gst_pad_event_default (pad, event);
- break;
+ }
}
+
+ GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
}
-static void
-pixbufscale_scale (GstPixbufScale * scale, unsigned char *dest,
- unsigned char *src)
+static GstFlowReturn
+gst_pixbufscale_transform (GstBaseTransform * trans,
+ GstBuffer * in, GstBuffer * out)
{
+ GstPixbufScale *scale;
GdkPixbuf *src_pixbuf, *dest_pixbuf;
- src_pixbuf = gdk_pixbuf_new_from_data
- (src, GDK_COLORSPACE_RGB, FALSE,
+ scale = GST_PIXBUFSCALE (trans);
+
+ src_pixbuf =
+ gdk_pixbuf_new_from_data (GST_BUFFER_DATA (in), GDK_COLORSPACE_RGB, FALSE,
8, scale->from_width, scale->from_height,
GST_RGB24_ROWSTRIDE (scale->from_width), NULL, NULL);
- dest_pixbuf = gdk_pixbuf_new_from_data
- (dest, GDK_COLORSPACE_RGB, FALSE,
- 8, scale->to_width, scale->to_height,
+
+ dest_pixbuf =
+ gdk_pixbuf_new_from_data (GST_BUFFER_DATA (out), GDK_COLORSPACE_RGB,
+ FALSE, 8, scale->to_width, scale->to_height,
GST_RGB24_ROWSTRIDE (scale->to_width), NULL, NULL);
- gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0, scale->to_width,
+
+ gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0,
+ scale->to_width,
scale->to_height, 0, 0,
(double) scale->to_width / scale->from_width,
(double) scale->to_height / scale->from_height, scale->gdk_method);
- dest_pixbuf = gdk_pixbuf_scale_simple
- (src_pixbuf, scale->to_width, scale->to_height, scale->gdk_method);
-
g_object_unref (src_pixbuf);
g_object_unref (dest_pixbuf);
+
+ return GST_FLOW_OK;
}
-static void
-gst_pixbufscale_chain (GstPad * pad, GstData * _data)
+static gboolean
+gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event)
{
- GstBuffer *buf = GST_BUFFER (_data);
GstPixbufScale *pixbufscale;
- guchar *data;
- gulong size;
- GstBuffer *outbuf;
-
- g_return_if_fail (pad != NULL);
- g_return_if_fail (GST_IS_PAD (pad));
- g_return_if_fail (buf != NULL);
+ gboolean ret;
+ double a;
+ GstStructure *structure;
pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
- g_return_if_fail (pixbufscale->inited);
-
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
-
- if (pixbufscale->passthru) {
- GST_LOG_OBJECT (pixbufscale, "passing through buffer of %ld bytes in '%s'",
- size, GST_OBJECT_NAME (pixbufscale));
- gst_pad_push (pixbufscale->srcpad, GST_DATA (buf));
- return;
- }
-
- GST_LOG_OBJECT (pixbufscale, "got buffer of %ld bytes in '%s'", size,
- GST_OBJECT_NAME (pixbufscale));
- GST_LOG_OBJECT (pixbufscale,
- "size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
- size, pixbufscale->from_width, pixbufscale->from_height,
- pixbufscale->to_width, pixbufscale->to_height, size,
- pixbufscale->from_buf_size, pixbufscale->to_buf_size);
-
- if (size != pixbufscale->from_buf_size) {
- GST_ERROR ("Incoming RGB data is %d bytes (expected: %d bytes) (%dx%d)\n",
- size, pixbufscale->from_buf_size, pixbufscale->from_width,
- pixbufscale->from_height);
- return;
- }
-
- outbuf = gst_pad_alloc_buffer_and_set_caps (pixbufscale->srcpad,
- GST_BUFFER_OFFSET_NONE, pixbufscale->to_buf_size);
-
- gst_buffer_stamp (outbuf, buf);
-
- pixbufscale_scale (pixbufscale, GST_BUFFER_DATA (outbuf), data);
-
- GST_DEBUG_OBJECT (pixbufscale, "pushing buffer of %d bytes in '%s'",
- GST_BUFFER_SIZE (outbuf), GST_OBJECT_NAME (pixbufscale));
- gst_pad_push (pixbufscale->srcpad, GST_DATA (outbuf));
+ GST_DEBUG_OBJECT (pixbufscale, "handling %s event",
+ GST_EVENT_TYPE_NAME (event));
- gst_buffer_unref (buf);
-}
-
-static void
-gst_pixbufscale_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstPixbufScale *src;
-
- g_return_if_fail (GST_IS_PIXBUFSCALE (object));
- src = GST_PIXBUFSCALE (object);
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NAVIGATION:
+ event =
+ GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
- switch (prop_id) {
- case ARG_METHOD:
- src->method = g_value_get_enum (value);
- switch (src->method) {
- case GST_PIXBUFSCALE_NEAREST:
- src->gdk_method = GDK_INTERP_NEAREST;
- break;
- case GST_PIXBUFSCALE_TILES:
- src->gdk_method = GDK_INTERP_TILES;
- break;
- case GST_PIXBUFSCALE_BILINEAR:
- src->gdk_method = GDK_INTERP_BILINEAR;
- break;
- case GST_PIXBUFSCALE_HYPER:
- src->gdk_method = GDK_INTERP_HYPER;
- break;
+ structure = (GstStructure *) gst_event_get_structure (event);
+ if (gst_structure_get_double (structure, "pointer_x", &a)) {
+ gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
+ a * pixbufscale->from_width / pixbufscale->to_width, NULL);
+ }
+ if (gst_structure_get_double (structure, "pointer_y", &a)) {
+ gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
+ a * pixbufscale->from_height / pixbufscale->to_height, NULL);
}
break;
default:
break;
}
-}
-static void
-gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstPixbufScale *src;
+ ret = gst_pad_event_default (pad, event);
- g_return_if_fail (GST_IS_PIXBUFSCALE (object));
- src = GST_PIXBUFSCALE (object);
+ gst_object_unref (pixbufscale);
- switch (prop_id) {
- case ARG_METHOD:
- g_value_set_enum (value, src->method);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ return ret;
}
-
gboolean
pixbufscale_init (GstPlugin * plugin)
{