From 5f91e70f0b5dde5b72a256e1dfcb7148d263be2f Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Fri, 1 Jul 2005 17:03:13 +0000 Subject: [PATCH] gst/videoscale/gstvideoscale.*: Clean up, port to 0.9. Derives from BaseTransform, implements a transform_caps. Remov... Original commit message from CVS: 2005-07-01 Andy Wingo * gst/videoscale/gstvideoscale.c: * gst/videoscale/gstvideoscale.h: Clean up, port to 0.9. Derives from BaseTransform, implements a transform_caps. Removed dead code including some PAR stuff that was never reached -- should probably be added back somehow. --- ChangeLog | 8 + gst/videoscale/gstvideoscale.c | 774 ++++++++++++--------------------- gst/videoscale/gstvideoscale.h | 26 +- 3 files changed, 289 insertions(+), 519 deletions(-) diff --git a/ChangeLog b/ChangeLog index ac7e2773e0..a6d9fae006 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2005-07-01 Andy Wingo + + * gst/videoscale/gstvideoscale.c: + * gst/videoscale/gstvideoscale.h: Clean up, port to 0.9. Derives + from BaseTransform, implements a transform_caps. Removed dead code + including some PAR stuff that was never reached -- should probably + be added back somehow. + 2005-07-01 Andy Wingo * gst/videoscale: Merge David's work from 0.8 branch. Changes to diff --git a/gst/videoscale/gstvideoscale.c b/gst/videoscale/gstvideoscale.c index 54d7189c5b..777d49dc3b 100644 --- a/gst/videoscale/gstvideoscale.c +++ b/gst/videoscale/gstvideoscale.c @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) 2005 David Schleef * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,13 +22,15 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "gstvideoscale.h" -#include #include +#include + +#include "gstvideoscale.h" #include "vs_image.h" + /* debug variable definition */ GST_DEBUG_CATEGORY (videoscale_debug); @@ -38,17 +41,10 @@ GST_ELEMENT_DETAILS ("Video scaler", "Resizes video", "Wim Taymans "); -/* GstVideoscale signals and args */ enum { - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_METHOD + PROP_0, + PROP_METHOD /* FILL ME */ }; @@ -97,7 +93,7 @@ gst_videoscale_method_get_type (void) static GEnumValue videoscale_methods[] = { {GST_VIDEOSCALE_POINT_SAMPLE, "0", "Point Sample (not implemented)"}, {GST_VIDEOSCALE_NEAREST, "1", "Nearest"}, - {GST_VIDEOSCALE_BILINEAR, "2", "Bilinear (not implemented)"}, + {GST_VIDEOSCALE_BILINEAR, "2", "Bilinear"}, {GST_VIDEOSCALE_BICUBIC, "3", "Bicubic (not implemented)"}, {0, NULL, NULL}, }; @@ -118,47 +114,51 @@ gst_videoscale_get_capslist (void) int i; caps = gst_caps_new_empty (); - for (i = 0; i < G_N_ELEMENTS (gst_videoscale_format_caps); i++) { + for (i = 0; i < G_N_ELEMENTS (gst_videoscale_format_caps); i++) gst_caps_append (caps, - gst_caps_copy (gst_static_caps_get (&gst_videoscale_format_caps[i]))); - } + gst_caps_make_writable + (gst_static_caps_get (&gst_videoscale_format_caps[i]))); } - return gst_caps_copy (caps); + return caps; } static GstPadTemplate * gst_videoscale_src_template_factory (void) { return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - gst_videoscale_get_capslist ()); + gst_caps_ref (gst_videoscale_get_capslist ())); } static GstPadTemplate * gst_videoscale_sink_template_factory (void) { return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - gst_videoscale_get_capslist ()); + gst_caps_ref (gst_videoscale_get_capslist ())); } + static void gst_videoscale_base_init (gpointer g_class); static void gst_videoscale_class_init (GstVideoscaleClass * klass); static void gst_videoscale_init (GstVideoscale * videoscale); static gboolean gst_videoscale_handle_src_event (GstPad * pad, GstEvent * event); +/* base transform */ +static GstCaps *gst_videoscale_transform_caps (GstBaseTransform * trans, + GstPad * pad, GstCaps * caps); +static gboolean gst_videoscale_set_caps (GstBaseTransform * trans, + GstCaps * in, GstCaps * out); +static GstFlowReturn gst_videoscale_transform (GstBaseTransform * trans, + GstBuffer * in, GstBuffer ** out); + static void gst_videoscale_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_videoscale_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_videoscale_finalize (GObject * object); - -static void gst_videoscale_chain (GstPad * pad, GstData * _data); -static GstCaps *gst_videoscale_get_capslist (void); static GstElementClass *parent_class = NULL; -/*static guint gst_videoscale_signals[LAST_SIGNAL] = { 0 }; */ GType gst_videoscale_get_type (void) @@ -179,7 +179,7 @@ gst_videoscale_get_type (void) }; videoscale_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstVideoscale", + g_type_register_static (GST_TYPE_BASE_TRANSFORM, "GstVideoscale", &videoscale_info, 0); } return videoscale_type; @@ -197,44 +197,89 @@ gst_videoscale_base_init (gpointer g_class) gst_element_class_add_pad_template (element_class, gst_videoscale_src_template_factory ()); } + static void gst_videoscale_class_init (GstVideoscaleClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; + GstBaseTransformClass *trans_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; + trans_class = (GstBaseTransformClass *) klass; - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD, g_param_spec_enum ("method", "method", "method", GST_TYPE_VIDEOSCALE_METHOD, 0, G_PARAM_READWRITE)); /* CHECKME! */ - - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); - - gobject_class->finalize = gst_videoscale_finalize; gobject_class->set_property = gst_videoscale_set_property; gobject_class->get_property = gst_videoscale_get_property; + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD, + g_param_spec_enum ("method", "method", "method", + GST_TYPE_VIDEOSCALE_METHOD, 0, G_PARAM_READWRITE)); + + trans_class->transform_caps = gst_videoscale_transform_caps; + trans_class->set_caps = gst_videoscale_set_caps; + trans_class->transform = gst_videoscale_transform; + + parent_class = g_type_class_peek_parent (klass); +} + +static void +gst_videoscale_init (GstVideoscale * videoscale) +{ + GstBaseTransform *trans = GST_BASE_TRANSFORM (videoscale); + + gst_pad_set_event_function (trans->srcpad, gst_videoscale_handle_src_event); + + videoscale->method = GST_VIDEOSCALE_NEAREST; + /*videoscale->method = GST_VIDEOSCALE_BILINEAR; */ + /*videoscale->method = GST_VIDEOSCALE_POINT_SAMPLE; */ +} + + +static void +gst_videoscale_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVideoscale *src = GST_VIDEOSCALE (object); + + switch (prop_id) { + case PROP_METHOD: + src->method = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_videoscale_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstVideoscale *src = GST_VIDEOSCALE (object); + + switch (prop_id) { + case PROP_METHOD: + g_value_set_enum (value, src->method); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static GstCaps * -gst_videoscale_getcaps (GstPad * pad) +gst_videoscale_transform_caps (GstBaseTransform * trans, GstPad * pad, + GstCaps * caps) { GstVideoscale *videoscale; - GstCaps *caps; - GstPad *otherpad; + GstCaps *ret; int i; - videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); + videoscale = GST_VIDEOSCALE (trans); - otherpad = (pad == videoscale->srcpad) ? videoscale->sinkpad : - videoscale->srcpad; - caps = gst_pad_get_allowed_caps (otherpad); + ret = gst_caps_make_writable (gst_caps_ref (caps)); - GST_DEBUG_OBJECT (pad, "othercaps of otherpad %s:%s are: %" GST_PTR_FORMAT, - GST_DEBUG_PAD_NAME (otherpad), caps); - - 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, @@ -242,347 +287,174 @@ gst_videoscale_getcaps (GstPad * pad) gst_structure_remove_field (structure, "pixel-aspect-ratio"); } - GST_DEBUG_OBJECT (pad, "returning caps: %" GST_PTR_FORMAT, caps); - return caps; + GST_DEBUG_OBJECT (pad, "returning caps: %" GST_PTR_FORMAT, ret); + return ret; } static int -gst_videoscale_get_format (const GstCaps * caps) +gst_videoscale_get_format (GstCaps * caps) { int i; - GstCaps *icaps; + GstCaps *icaps, *scaps; for (i = 0; i < G_N_ELEMENTS (gst_videoscale_format_caps); i++) { - icaps = gst_caps_intersect (caps, - gst_static_caps_get (&gst_videoscale_format_caps[i])); + scaps = gst_static_caps_get (&gst_videoscale_format_caps[i]); + icaps = gst_caps_intersect (caps, scaps); if (!gst_caps_is_empty (icaps)) { - gst_caps_free (icaps); + gst_caps_unref (icaps); return i; } - gst_caps_free (icaps); + gst_caps_unref (icaps); } return -1; } -static GstPadLinkReturn -gst_videoscale_link (GstPad * pad, const GstCaps * caps) -{ - GstVideoscale *videoscale; - GstPadLinkReturn ret; - GstPad *otherpad; - GstCaps *othercaps, *newcaps; - GstStructure *otherstructure, *structure, *newstructure; - int format; - int height = 0, width = 0, newwidth, newheight; - const GValue *par = NULL, *otherpar; - - GST_DEBUG_OBJECT (pad, "_link with caps %" GST_PTR_FORMAT, caps); - videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); - - otherpad = (pad == videoscale->srcpad) ? videoscale->sinkpad : - videoscale->srcpad; - - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", &width); - ret &= gst_structure_get_int (structure, "height", &height); - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - - format = gst_videoscale_get_format (caps); - - if (!ret || format == -1) - return GST_PAD_LINK_REFUSED; - - GST_DEBUG_OBJECT (videoscale, - "trying to set caps %" GST_PTR_FORMAT " on pad %s:%s for passthru", - caps, GST_DEBUG_PAD_NAME (otherpad)); - - ret = gst_pad_try_set_caps (otherpad, caps); - if (GST_PAD_LINK_SUCCESSFUL (ret)) { - /* cool, we can use passthru */ - GST_DEBUG_OBJECT (videoscale, "passthru works"); - GST_FLAG_SET (videoscale, GST_ELEMENT_WORK_IN_PLACE); - - videoscale->passthru = TRUE; - newwidth = width; - newheight = height; - - goto beach; - } - - GST_FLAG_UNSET (videoscale, GST_ELEMENT_WORK_IN_PLACE); - - /* no passthru, so try to convert */ - GST_DEBUG_OBJECT (videoscale, "no passthru"); - - /* copy caps to find which one works for the otherpad */ - newcaps = gst_caps_copy (caps); - newstructure = gst_caps_get_structure (newcaps, 0); - - /* iterate over other pad's caps, find a nice conversion. - * For calculations, we only use the first because we - * (falsely) assume that all caps have the same PAR and - * size values. */ - othercaps = gst_pad_get_allowed_caps (otherpad); - otherstructure = gst_caps_get_structure (othercaps, 0); - otherpar = gst_structure_get_value (otherstructure, "pixel-aspect-ratio"); - if (par && otherpar) { - gint num, den, onum, oden; - gboolean keep_h, w_align, h_align, w_inc; - - /* otherpar can be a list */ - if (G_VALUE_TYPE (otherpar) == GST_TYPE_LIST) - otherpar = gst_value_list_get_value (otherpar, 0); - - num = gst_value_get_fraction_numerator (par); - den = gst_value_get_fraction_denominator (par); - onum = gst_value_get_fraction_numerator (otherpar); - oden = gst_value_get_fraction_denominator (otherpar); - w_align = (width * num * oden % (den * onum) == 0); - h_align = (height * den * onum % (num * oden) == 0); - w_inc = (num * oden > den * onum); - - /* decide whether to change width or height */ - if (w_align && w_inc) - keep_h = TRUE; - else if (h_align && !w_inc) - keep_h = FALSE; - else if (w_align) - keep_h = TRUE; - else if (h_align) - keep_h = FALSE; - else - keep_h = w_inc; - - /* take par into effect */ - if (keep_h) { - newwidth = width * num / den; - newheight = height; - } else { - newwidth = width; - newheight = height * den / num; - } - } else { - /* (at least) one has no par, so it should accept the other */ - newwidth = width; - newheight = height; - } - - /* size: don't check return values. We honestly don't care. */ - gst_structure_set_value (newstructure, "width", - gst_structure_get_value (otherstructure, "width")); - gst_structure_set_value (newstructure, "height", - gst_structure_get_value (otherstructure, "height")); - gst_caps_structure_fixate_field_nearest_int (newstructure, "width", newwidth); - gst_caps_structure_fixate_field_nearest_int (newstructure, - "height", newheight); - gst_structure_get_int (newstructure, "width", &newwidth); - gst_structure_get_int (newstructure, "height", &newheight); - - /* obviously, keep PAR if we got one */ - if (otherpar) - gst_structure_set_value (newstructure, "pixel-aspect-ratio", otherpar); - GST_DEBUG_OBJECT (videoscale, - "trying to set caps %" GST_PTR_FORMAT " on pad %s:%s for non-passthru", - caps, GST_DEBUG_PAD_NAME (otherpad)); - - /* try - bail out if fail */ - ret = gst_pad_try_set_caps (otherpad, newcaps); - if (GST_PAD_LINK_FAILED (ret)) - return ret; - - videoscale->passthru = FALSE; - -beach: - /* whee, works. Save for use in _chain and get moving. */ - if (pad == videoscale->srcpad) { - videoscale->to_width = width; - videoscale->to_height = height; - videoscale->from_width = newwidth; - videoscale->from_height = newheight; - } else { - videoscale->from_width = width; - videoscale->from_height = height; - videoscale->to_width = newwidth; - videoscale->to_height = newheight; - } - videoscale->format = format; - - GST_DEBUG_OBJECT (videoscale, "work completed"); - - return GST_PAD_LINK_OK; -} - -static GstCaps * -gst_videoscale_src_fixate (GstPad * pad, const GstCaps * caps) -{ - GstVideoscale *videoscale; - GstCaps *newcaps; - int i; - gboolean ret = TRUE; - - videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (pad, "asked to fixate caps %" GST_PTR_FORMAT, caps); - - /* don't mess with fixation if we don't have a sink pad PAR */ - if (!videoscale->from_par) { - GST_DEBUG_OBJECT (videoscale, "no PAR to scale from, not fixating"); - return NULL; - } - - /* for each structure, if it contains a pixel aspect ratio, - * fix width and height */ - - newcaps = gst_caps_copy (caps); - for (i = 0; i < gst_caps_get_size (newcaps); i++) { - const GValue *to_par; - - GstStructure *structure = gst_caps_get_structure (newcaps, i); - - to_par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - if (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; - - int w = 0, h = 0; - int num, den; - - /* if both width and height are already fixed, we can't do anything - * about it anymore */ - if (gst_structure_get_int (structure, "width", &w)) - ++count; - if (gst_structure_get_int (structure, "height", &h)) - ++count; - if (count == 2) { - GST_DEBUG_OBJECT (videoscale, - "dimensions already set to %dx%d, not fixating", w, h); - return NULL; - } - - from_w = videoscale->from_width; - from_h = videoscale->from_height; - from_par_n = gst_value_get_fraction_numerator (videoscale->from_par); - from_par_d = gst_value_get_fraction_denominator (videoscale->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 (videoscale, - "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 (videoscale, - "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 (videoscale, "keeping video height"); - h = from_h; - w = h * num / den; - } else if (from_w % num == 0) { - GST_DEBUG_OBJECT (videoscale, "keeping video width"); - w = from_w; - h = w * den / num; - } else { - GST_DEBUG_OBJECT (videoscale, "approximating but keeping video height"); - h = from_h; - w = h * num / den; - } - GST_DEBUG_OBJECT (videoscale, "scaling to %dx%d", w, h); - - /* now fixate */ - ret &= - gst_caps_structure_fixate_field_nearest_int (structure, "width", w); - ret &= - gst_caps_structure_fixate_field_nearest_int (structure, "height", h); - } - } - - if (ret) - return newcaps; - - gst_caps_free (newcaps); - return NULL; -} - -static void -gst_videoscale_init (GstVideoscale * videoscale) -{ - GST_DEBUG_OBJECT (videoscale, "_init"); - videoscale->sinkpad = - gst_pad_new_from_template (gst_videoscale_sink_template_factory (), - "sink"); - gst_element_add_pad (GST_ELEMENT (videoscale), videoscale->sinkpad); - gst_pad_set_chain_function (videoscale->sinkpad, gst_videoscale_chain); - gst_pad_set_link_function (videoscale->sinkpad, gst_videoscale_link); - gst_pad_set_getcaps_function (videoscale->sinkpad, gst_videoscale_getcaps); - - videoscale->srcpad = - gst_pad_new_from_template (gst_videoscale_src_template_factory (), "src"); - gst_element_add_pad (GST_ELEMENT (videoscale), videoscale->srcpad); - gst_pad_set_event_function (videoscale->srcpad, - gst_videoscale_handle_src_event); - gst_pad_set_link_function (videoscale->srcpad, gst_videoscale_link); - gst_pad_set_getcaps_function (videoscale->srcpad, gst_videoscale_getcaps); - gst_pad_set_fixate_function (videoscale->srcpad, gst_videoscale_src_fixate); - - videoscale->method = GST_VIDEOSCALE_NEAREST; - /*videoscale->method = GST_VIDEOSCALE_BILINEAR; */ - /*videoscale->method = GST_VIDEOSCALE_POINT_SAMPLE; */ -} - static gboolean -gst_videoscale_handle_src_event (GstPad * pad, GstEvent * event) +gst_videoscale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) { GstVideoscale *videoscale; - double a; + gboolean ret; GstStructure *structure; - videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); + videoscale = GST_VIDEOSCALE (trans); - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NAVIGATION: - event = GST_EVENT (gst_data_copy_on_write (GST_DATA (event))); - structure = event->event_data.structure.structure; - if (gst_structure_get_double (structure, "pointer_x", &a)) { - gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, - a * videoscale->from_width / videoscale->to_width, NULL); - } - if (gst_structure_get_double (structure, "pointer_y", &a)) { - gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, - a * videoscale->from_height / videoscale->to_height, NULL); - } - return gst_pad_event_default (pad, event); - break; - default: - GST_DEBUG_OBJECT (videoscale, "passing on non-NAVIGATION event %p", - event); - return gst_pad_event_default (pad, event); - break; - } + structure = gst_caps_get_structure (in, 0); + ret = gst_structure_get_int (structure, "width", &videoscale->from_width); + ret &= gst_structure_get_int (structure, "height", &videoscale->from_height); + + structure = gst_caps_get_structure (out, 0); + ret &= gst_structure_get_int (structure, "width", &videoscale->to_width); + ret &= gst_structure_get_int (structure, "height", &videoscale->to_height); + + /* fixme: par */ + GST_DEBUG_OBJECT (videoscale, "from=%dx%d to=%dx%d", + videoscale->from_width, videoscale->from_height, + videoscale->to_width, videoscale->to_height); + + videoscale->format = gst_videoscale_get_format (in); + + return ret; } #define ROUND_UP_2(x) (((x)+1)&~1) #define ROUND_UP_4(x) (((x)+3)&~3) #define ROUND_UP_8(x) (((x)+7)&~7) -static void -gst_videoscale_chain (GstPad * pad, GstData * _data) +/* returns size of output buffer */ +static gulong +gst_videoscale_prepare_sizes (GstVideoscale * videoscale, VSImage * src, + VSImage * dest, gboolean reset_source) +{ + gulong size = 0; + + if (reset_source) { + src->width = videoscale->from_width; + src->height = videoscale->from_height; + } + + dest->width = videoscale->to_width; + dest->height = videoscale->to_height; + + switch (videoscale->format) { + case GST_VIDEOSCALE_RGBx: + case GST_VIDEOSCALE_xRGB: + case GST_VIDEOSCALE_BGRx: + case GST_VIDEOSCALE_xBGR: + case GST_VIDEOSCALE_AYUV: + src->stride = src->width * 4; + dest->stride = dest->width * 4; + size = dest->stride * dest->height; + break; + case GST_VIDEOSCALE_RGB: + case GST_VIDEOSCALE_BGR: + src->stride = ROUND_UP_4 (src->width * 3); + dest->stride = ROUND_UP_4 (dest->width * 3); + size = dest->stride * dest->height; + break; + case GST_VIDEOSCALE_YUY2: + case GST_VIDEOSCALE_YVYU: + case GST_VIDEOSCALE_UYVY: + src->stride = ROUND_UP_4 (src->width * 2); + dest->stride = ROUND_UP_4 (dest->width * 2); + size = dest->stride * dest->height; + break; + case GST_VIDEOSCALE_Y: + src->stride = ROUND_UP_4 (src->width); + dest->stride = ROUND_UP_4 (dest->width); + size = dest->stride * dest->height; + break; + case GST_VIDEOSCALE_I420: + case GST_VIDEOSCALE_YV12: + { + gulong dest_u_stride; + gulong dest_u_height; + + src->stride = ROUND_UP_4 (src->width); + dest->stride = ROUND_UP_4 (dest->width); + + dest_u_height = ROUND_UP_2 (dest->height) / 2; + dest_u_stride = ROUND_UP_4 (dest->stride / 2); + + size = dest->stride * ROUND_UP_2 (dest->height) + + 2 * dest_u_stride * dest_u_height; + break; + } + case GST_VIDEOSCALE_RGB565: + src->stride = ROUND_UP_4 (src->width * 2); + dest->stride = ROUND_UP_4 (dest->width * 2); + size = dest->stride * dest->height; + break; + case GST_VIDEOSCALE_RGB555: + src->stride = ROUND_UP_4 (src->width * 2); + dest->stride = ROUND_UP_4 (dest->width * 2); + size = dest->stride * dest->height; + break; + default: + g_warning ("don't know how to scale"); + break; + } + + return size; +} + +static void +gst_videoscale_prepare_images (GstVideoscale * videoscale, GstBuffer * in, + GstBuffer * out, VSImage * src, VSImage * src_u, VSImage * src_v, + VSImage * dest, VSImage * dest_u, VSImage * dest_v) +{ + src->pixels = GST_BUFFER_DATA (in); + dest->pixels = GST_BUFFER_DATA (out); + + switch (videoscale->format) { + case GST_VIDEOSCALE_I420: + case GST_VIDEOSCALE_YV12: + src_u->pixels = src->pixels + ROUND_UP_2 (src->height) * src->stride; + src_u->height = ROUND_UP_2 (src->height) / 2; + src_u->width = ROUND_UP_2 (src->width) / 2; + src_u->stride = ROUND_UP_4 (src->stride / 2); + memcpy (src_v, src_u, sizeof (src_v)); + src_v->pixels = src_u->pixels + src_u->height * src_u->stride; + + dest_u->pixels = dest->pixels + ROUND_UP_2 (dest->height) * dest->stride; + dest_u->height = ROUND_UP_2 (dest->height) / 2; + dest_u->width = ROUND_UP_2 (dest->width) / 2; + dest_u->stride = ROUND_UP_4 (dest->stride / 2); + memcpy (dest_v, dest_u, sizeof (dest_v)); + dest_v->pixels = dest_u->pixels + dest_u->height * dest_u->stride; + break; + default: + break; + } +} + +static GstFlowReturn +gst_videoscale_transform (GstBaseTransform * trans, GstBuffer * in, + GstBuffer ** out) { - GstBuffer *buf = GST_BUFFER (_data); GstVideoscale *videoscale; + GstFlowReturn ret; gulong size; - GstBuffer *outbuf; VSImage dest; VSImage src; VSImage dest_u; @@ -591,109 +463,28 @@ gst_videoscale_chain (GstPad * pad, GstData * _data) VSImage src_v; guint8 *tmpbuf; - g_return_if_fail (pad != NULL); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); + videoscale = GST_VIDEOSCALE (trans); - videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); + /* FIXME: I can't figure out how passthru would work in 0.9 */ - if (videoscale->passthru) { - gst_pad_push (videoscale->srcpad, GST_DATA (buf)); - return; + size = gst_videoscale_prepare_sizes (videoscale, &src, &dest, TRUE); + if (!size) { + ret = GST_FLOW_UNEXPECTED; + goto done; } - GST_LOG_OBJECT (videoscale, - "from=%dx%d to=%dx%d", - videoscale->from_width, videoscale->from_height, - videoscale->to_width, videoscale->to_height); + *out = NULL; + ret = gst_pad_alloc_buffer (trans->srcpad, + GST_BUFFER_OFFSET_NONE, size, GST_PAD_CAPS (trans->srcpad), out); + if (ret != GST_FLOW_OK) + goto done; + gst_buffer_stamp (*out, in); - src.pixels = GST_BUFFER_DATA (buf); - src.width = videoscale->from_width; - src.height = videoscale->from_height; + /* output size could have changed, prepare again */ + gst_videoscale_prepare_sizes (videoscale, &src, &dest, FALSE); - dest.width = videoscale->to_width; - dest.height = videoscale->to_height; - - switch (videoscale->format) { - case GST_VIDEOSCALE_RGBx: - case GST_VIDEOSCALE_xRGB: - case GST_VIDEOSCALE_BGRx: - case GST_VIDEOSCALE_xBGR: - case GST_VIDEOSCALE_AYUV: - src.stride = videoscale->from_width * 4; - dest.stride = videoscale->to_width * 4; - size = dest.stride * dest.height; - break; - case GST_VIDEOSCALE_RGB: - case GST_VIDEOSCALE_BGR: - src.stride = ROUND_UP_4 (videoscale->from_width * 3); - dest.stride = ROUND_UP_4 (videoscale->to_width * 3); - size = dest.stride * dest.height; - break; - case GST_VIDEOSCALE_YUY2: - case GST_VIDEOSCALE_YVYU: - case GST_VIDEOSCALE_UYVY: - src.stride = ROUND_UP_4 (videoscale->from_width * 2); - dest.stride = ROUND_UP_4 (videoscale->to_width * 2); - size = dest.stride * dest.height; - break; - case GST_VIDEOSCALE_Y: - src.stride = ROUND_UP_4 (videoscale->from_width); - dest.stride = ROUND_UP_4 (videoscale->to_width); - size = dest.stride * dest.height; - break; - case GST_VIDEOSCALE_I420: - case GST_VIDEOSCALE_YV12: - src.stride = ROUND_UP_4 (videoscale->from_width); - dest.stride = ROUND_UP_4 (videoscale->to_width); - - src_u.pixels = src.pixels + ROUND_UP_2 (src.height) * src.stride; - src_u.height = ROUND_UP_2 (src.height) / 2; - src_u.width = ROUND_UP_2 (src.width) / 2; - src_u.stride = ROUND_UP_4 (src.stride / 2); - - dest_u.height = ROUND_UP_2 (dest.height) / 2; - dest_u.width = ROUND_UP_2 (dest.width) / 2; - dest_u.stride = ROUND_UP_4 (dest.stride / 2); - - memcpy (&src_v, &src_u, sizeof (src_v)); - src_v.pixels = src_u.pixels + src_u.height * src_u.stride; - - memcpy (&dest_v, &dest_u, sizeof (dest_v)); - - size = dest.stride * ROUND_UP_2 (dest.height) + - 2 * dest_u.stride * dest_u.height; - break; - case GST_VIDEOSCALE_RGB565: - src.stride = ROUND_UP_4 (videoscale->from_width * 2); - dest.stride = ROUND_UP_4 (videoscale->to_width * 2); - size = dest.stride * dest.height; - break; - case GST_VIDEOSCALE_RGB555: - src.stride = ROUND_UP_4 (videoscale->from_width * 2); - dest.stride = ROUND_UP_4 (videoscale->to_width * 2); - size = dest.stride * dest.height; - break; - default: - g_warning ("don't know how to scale"); - gst_buffer_unref (buf); - return; - } - - outbuf = gst_pad_alloc_buffer (videoscale->srcpad, - GST_BUFFER_OFFSET_NONE, size); - gst_buffer_stamp (outbuf, buf); - - dest.pixels = GST_BUFFER_DATA (outbuf); - switch (videoscale->format) { - case GST_VIDEOSCALE_I420: - case GST_VIDEOSCALE_YV12: - dest_u.pixels = dest.pixels + ROUND_UP_2 (dest.height) * dest.stride; - dest_v.pixels = dest_u.pixels + dest_u.height * dest_u.stride; - break; - default: - break; - } + gst_videoscale_prepare_images (videoscale, in, *out, &src, &src_u, &src_v, + &dest, &dest_u, &dest_v); tmpbuf = g_malloc (dest.stride * 2); @@ -787,66 +578,41 @@ gst_videoscale_chain (GstPad * pad, GstData * _data) g_free (tmpbuf); GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes", - GST_BUFFER_SIZE (outbuf)); + GST_BUFFER_SIZE (*out)); - gst_pad_push (videoscale->srcpad, GST_DATA (outbuf)); - - gst_buffer_unref (buf); +done: + gst_buffer_unref (in); + return ret; } -static void -gst_videoscale_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstVideoscale *src; - - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_VIDEOSCALE (object)); - src = GST_VIDEOSCALE (object); - - GST_DEBUG_OBJECT (src, "gst_videoscale_set_property"); - switch (prop_id) { - case ARG_METHOD: - src->method = g_value_get_enum (value); - break; - default: - break; - } -} - -static void -gst_videoscale_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstVideoscale *src; - - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_VIDEOSCALE (object)); - src = GST_VIDEOSCALE (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; - } -} - -/* maybe these free's should go in a state change instead; - * in that case, we'd probably also want to clear from/to width/height there. */ -static void -gst_videoscale_finalize (GObject * object) +static gboolean +gst_videoscale_handle_src_event (GstPad * pad, GstEvent * event) { GstVideoscale *videoscale; + double a; + GstStructure *structure; - videoscale = GST_VIDEOSCALE (object); + videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); - g_free (videoscale->from_par); - g_free (videoscale->to_par); - - G_OBJECT_CLASS (parent_class)->finalize (object); + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NAVIGATION: + event = + GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); + structure = event->event_data.structure.structure; + if (gst_structure_get_double (structure, "pointer_x", &a)) { + gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, + a * videoscale->from_width / videoscale->to_width, NULL); + } + if (gst_structure_get_double (structure, "pointer_y", &a)) { + gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, + a * videoscale->from_height / videoscale->to_height, NULL); + } + return gst_pad_event_default (pad, event); + default: + GST_DEBUG_OBJECT (videoscale, "passing on non-NAVIGATION event %p", + event); + return gst_pad_event_default (pad, event); + } } static gboolean diff --git a/gst/videoscale/gstvideoscale.h b/gst/videoscale/gstvideoscale.h index ca7563c9e2..931a4becbf 100644 --- a/gst/videoscale/gstvideoscale.h +++ b/gst/videoscale/gstvideoscale.h @@ -23,16 +23,16 @@ #include +#include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS + -/* debugging */ GST_DEBUG_CATEGORY_EXTERN (videoscale_debug); #define GST_CAT_DEFAULT videoscale_debug + #define GST_TYPE_VIDEOSCALE \ (gst_videoscale_get_type()) #define GST_VIDEOSCALE(obj) \ @@ -44,6 +44,7 @@ GST_DEBUG_CATEGORY_EXTERN (videoscale_debug); #define GST_IS_VIDEOSCALE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEOSCALE)) + typedef enum { GST_VIDEOSCALE_POINT_SAMPLE, GST_VIDEOSCALE_NEAREST, @@ -51,13 +52,13 @@ typedef enum { GST_VIDEOSCALE_BICUBIC } GstVideoScaleMethod; + typedef struct _GstVideoscale GstVideoscale; typedef struct _GstVideoscaleClass GstVideoscaleClass; -struct _GstVideoscale { - GstElement element; - GstPad *sinkpad,*srcpad; +struct _GstVideoscale { + GstBaseTransform element; /* video state */ gboolean inited; @@ -66,8 +67,6 @@ struct _GstVideoscale { gint to_height; gint from_width; gint from_height; - GValue *to_par; /* pixel aspect ratio of sink pad */ - GValue *from_par; /* pixel aspect ratio of src pad */ gboolean passthru; float framerate; @@ -78,17 +77,14 @@ struct _GstVideoscale { }; struct _GstVideoscaleClass { - GstElementClass parent_class; + GstBaseTransformClass parent_class; }; + GType gst_videoscale_get_type(void); -void gst_videoscale_setup(GstVideoscale *); -#define gst_videoscale_scale(scale, src, dest) (scale)->scale_cc((scale), (src), (dest)) -#ifdef __cplusplus -} -#endif /* __cplusplus */ +G_END_DECLS #endif /* __GST_VIDEOSCALE_H__ */