| /* GStreamer |
| * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> |
| * Copyright (C) 2005 David Schleef <ds@schleef.org> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * 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. |
| */ |
| |
| /** |
| * SECTION:element-videoscale |
| * @see_also: videorate, videoconvert |
| * |
| * <refsect2> |
| * <para> |
| * This element resizes video frames. By default the element will try to |
| * negotiate to the same size on the source and sinkpad so that no scaling |
| * is needed. It is therefore safe to insert this element in a pipeline to |
| * get more robust behaviour without any cost if no scaling is needed. |
| * </para> |
| * <para> |
| * This element supports a wide range of color spaces including various YUV and |
| * RGB formats and is therefore generally able to operate anywhere in a |
| * pipeline. |
| * </para> |
| * <title>Example pipelines</title> |
| * <para> |
| * <programlisting> |
| * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videoconvert ! videoscale ! ximagesink |
| * </programlisting> |
| * Decode an Ogg/Theora and display the video using ximagesink. Since |
| * ximagesink cannot perform scaling, the video scaling will be performed by |
| * videoscale when you resize the video window. |
| * To create the test Ogg/Theora file refer to the documentation of theoraenc. |
| * </para> |
| * <para> |
| * <programlisting> |
| * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videoscale ! video/x-raw-yuv, width=50 ! xvimagesink |
| * </programlisting> |
| * Decode an Ogg/Theora and display the video using xvimagesink with a width of |
| * 50. |
| * </para> |
| * </refsect2> |
| * |
| * Last reviewed on 2006-03-02 (0.10.4) |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <string.h> |
| |
| #include <gst/gst.h> |
| #include <gst/video/video.h> |
| #include <gst/base/gstbasetransform.h> |
| #include <cog/cog.h> |
| #include <cog/cogvirtframe.h> |
| #include "gstcogutils.h" |
| |
| GST_DEBUG_CATEGORY_STATIC (cog_scale_debug); |
| #define GST_CAT_DEFAULT cog_scale_debug |
| |
| #define GST_TYPE_COG_SCALE \ |
| (gst_cog_scale_get_type()) |
| #define GST_COG_SCALE(obj) \ |
| (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_COG_SCALE,GstCogScale)) |
| #define GST_COG_SCALE_CLASS(klass) \ |
| (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_COG_SCALE,GstCogScaleClass)) |
| #define GST_IS_COG_SCALE(obj) \ |
| (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_COG_SCALE)) |
| #define GST_IS_COG_SCALE_CLASS(klass) \ |
| (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_COG_SCALE)) |
| |
| typedef struct _GstCogScale GstCogScale; |
| typedef struct _GstCogScaleClass GstCogScaleClass; |
| |
| /** |
| * GstCogScale: |
| * |
| * Opaque data structure |
| */ |
| struct _GstCogScale |
| { |
| GstBaseTransform element; |
| |
| int quality; |
| |
| /* negotiated stuff */ |
| GstVideoFormat format; |
| guint src_size; |
| guint dest_size; |
| gint to_width; |
| gint to_height; |
| gint from_width; |
| gint from_height; |
| |
| /*< private > */ |
| }; |
| |
| struct _GstCogScaleClass |
| { |
| GstBaseTransformClass parent_class; |
| }; |
| |
| GType gst_cog_scale_get_type (void); |
| |
| #define DEFAULT_QUALITY 5 |
| |
| enum |
| { |
| PROP_0, |
| PROP_QUALITY |
| }; |
| |
| /* can't handle width/height of 1 yet, since we divide a lot by (n-1) */ |
| #undef GST_VIDEO_SIZE_RANGE |
| #define GST_VIDEO_SIZE_RANGE "(int) [ 2, MAX ]" |
| |
| #define TEMPLATE_CAPS \ |
| GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, AYUV, Y42B }") ";" \ |
| GST_VIDEO_CAPS_ARGB) |
| |
| static GstStaticPadTemplate gst_cog_scale_src_template = |
| GST_STATIC_PAD_TEMPLATE ("src", |
| GST_PAD_SRC, |
| GST_PAD_ALWAYS, |
| TEMPLATE_CAPS); |
| |
| static GstStaticPadTemplate gst_cog_scale_sink_template = |
| GST_STATIC_PAD_TEMPLATE ("sink", |
| GST_PAD_SINK, |
| GST_PAD_ALWAYS, |
| TEMPLATE_CAPS); |
| |
| static void gst_cog_scale_base_init (gpointer g_class); |
| static void gst_cog_scale_class_init (GstCogScaleClass * klass); |
| static void gst_cog_scale_init (GstCogScale * videoscale); |
| static void gst_cog_scale_finalize (GstCogScale * videoscale); |
| static gboolean gst_cog_scale_src_event (GstBaseTransform * trans, |
| GstEvent * event); |
| |
| /* base transform vmethods */ |
| static GstCaps *gst_cog_scale_transform_caps (GstBaseTransform * trans, |
| GstPadDirection direction, GstCaps * caps); |
| static gboolean gst_cog_scale_set_caps (GstBaseTransform * trans, |
| GstCaps * in, GstCaps * out); |
| static gboolean gst_cog_scale_get_unit_size (GstBaseTransform * trans, |
| GstCaps * caps, guint * size); |
| static GstFlowReturn gst_cog_scale_transform (GstBaseTransform * trans, |
| GstBuffer * in, GstBuffer * out); |
| static void gst_cog_scale_fixate_caps (GstBaseTransform * base, |
| GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); |
| |
| static void gst_cog_scale_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec); |
| static void gst_cog_scale_get_property (GObject * object, guint prop_id, |
| GValue * value, GParamSpec * pspec); |
| |
| static GstElementClass *parent_class = NULL; |
| |
| |
| GType |
| gst_cog_scale_get_type (void) |
| { |
| static GType cog_scale_type = 0; |
| |
| if (!cog_scale_type) { |
| static const GTypeInfo cog_scale_info = { |
| sizeof (GstCogScaleClass), |
| gst_cog_scale_base_init, |
| NULL, |
| (GClassInitFunc) gst_cog_scale_class_init, |
| NULL, |
| NULL, |
| sizeof (GstCogScale), |
| 0, |
| (GInstanceInitFunc) gst_cog_scale_init, |
| }; |
| |
| cog_scale_type = |
| g_type_register_static (GST_TYPE_BASE_TRANSFORM, "GstCogScale", |
| &cog_scale_info, 0); |
| |
| GST_DEBUG_CATEGORY_INIT (cog_scale_debug, "cogscale", 0, "Cog scale"); |
| } |
| return cog_scale_type; |
| } |
| |
| static void |
| gst_cog_scale_base_init (gpointer g_class) |
| { |
| GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); |
| |
| gst_element_class_set_metadata (element_class, "Video scaler", |
| "Filter/Effect/Video", |
| "Resizes video", "Wim Taymans <wim.taymans@chello.be>"); |
| |
| gst_element_class_add_pad_template (element_class, |
| gst_static_pad_template_get (&gst_cog_scale_src_template)); |
| gst_element_class_add_pad_template (element_class, |
| gst_static_pad_template_get (&gst_cog_scale_sink_template)); |
| } |
| |
| static void |
| gst_cog_scale_class_init (GstCogScaleClass * klass) |
| { |
| GObjectClass *gobject_class; |
| GstBaseTransformClass *trans_class; |
| |
| gobject_class = (GObjectClass *) klass; |
| trans_class = (GstBaseTransformClass *) klass; |
| |
| gobject_class->finalize = (GObjectFinalizeFunc) gst_cog_scale_finalize; |
| gobject_class->set_property = gst_cog_scale_set_property; |
| gobject_class->get_property = gst_cog_scale_get_property; |
| |
| g_object_class_install_property (gobject_class, PROP_QUALITY, |
| g_param_spec_int ("quality", "quality", "Scaling Quality", |
| 0, 10, DEFAULT_QUALITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
| |
| trans_class->transform_caps = |
| GST_DEBUG_FUNCPTR (gst_cog_scale_transform_caps); |
| trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_cog_scale_set_caps); |
| trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_cog_scale_get_unit_size); |
| trans_class->transform = GST_DEBUG_FUNCPTR (gst_cog_scale_transform); |
| trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_cog_scale_fixate_caps); |
| trans_class->src_event = GST_DEBUG_FUNCPTR (gst_cog_scale_src_event); |
| |
| trans_class->passthrough_on_same_caps = TRUE; |
| |
| parent_class = g_type_class_peek_parent (klass); |
| } |
| |
| static void |
| gst_cog_scale_init (GstCogScale * videoscale) |
| { |
| gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (videoscale), TRUE); |
| videoscale->quality = DEFAULT_QUALITY; |
| } |
| |
| static void |
| gst_cog_scale_finalize (GstCogScale * videoscale) |
| { |
| G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (videoscale)); |
| } |
| |
| static void |
| gst_cog_scale_set_property (GObject * object, guint prop_id, |
| const GValue * value, GParamSpec * pspec) |
| { |
| GstCogScale *vscale = GST_COG_SCALE (object); |
| |
| switch (prop_id) { |
| case PROP_QUALITY: |
| GST_OBJECT_LOCK (vscale); |
| vscale->quality = g_value_get_int (value); |
| GST_OBJECT_UNLOCK (vscale); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gst_cog_scale_get_property (GObject * object, guint prop_id, GValue * value, |
| GParamSpec * pspec) |
| { |
| GstCogScale *vscale = GST_COG_SCALE (object); |
| |
| switch (prop_id) { |
| case PROP_QUALITY: |
| GST_OBJECT_LOCK (vscale); |
| g_value_set_int (value, vscale->quality); |
| GST_OBJECT_UNLOCK (vscale); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static GstCaps * |
| gst_cog_scale_transform_caps (GstBaseTransform * trans, |
| GstPadDirection direction, GstCaps * caps) |
| { |
| GstCaps *ret; |
| GstStructure *structure; |
| const GValue *par; |
| |
| /* this function is always called with a simple caps */ |
| g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL); |
| |
| structure = gst_caps_get_structure (caps, 0); |
| |
| ret = gst_caps_copy (caps); |
| structure = gst_caps_get_structure (ret, 0); |
| |
| gst_structure_set (structure, |
| "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, |
| "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); |
| |
| /* if pixel aspect ratio, make a range of it */ |
| if ((par = gst_structure_get_value (structure, "pixel-aspect-ratio"))) { |
| GstCaps *copy; |
| GstStructure *cstruct; |
| |
| /* copy input PAR first, this is the prefered PAR */ |
| gst_structure_set_value (structure, "pixel-aspect-ratio", par); |
| |
| /* then make a copy with a fraction range as a second choice */ |
| copy = gst_caps_copy (ret); |
| cstruct = gst_caps_get_structure (copy, 0); |
| gst_structure_set (cstruct, |
| "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); |
| |
| /* and append */ |
| gst_caps_append (ret, copy); |
| } |
| |
| GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret); |
| |
| return ret; |
| } |
| |
| static gboolean |
| gst_cog_scale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) |
| { |
| GstCogScale *videoscale; |
| gboolean ret; |
| |
| videoscale = GST_COG_SCALE (trans); |
| |
| ret = gst_video_format_parse_caps (in, &videoscale->format, |
| &videoscale->from_width, &videoscale->from_height); |
| ret &= gst_video_format_parse_caps (out, NULL, |
| &videoscale->to_width, &videoscale->to_height); |
| if (!ret) |
| goto done; |
| |
| videoscale->src_size = gst_video_format_get_size (videoscale->format, |
| videoscale->from_width, videoscale->from_height); |
| videoscale->dest_size = gst_video_format_get_size (videoscale->format, |
| videoscale->to_width, videoscale->to_height); |
| |
| /* FIXME: par */ |
| GST_DEBUG_OBJECT (videoscale, "from=%dx%d, size %d -> to=%dx%d, size %d", |
| videoscale->from_width, videoscale->from_height, videoscale->src_size, |
| videoscale->to_width, videoscale->to_height, videoscale->dest_size); |
| |
| done: |
| return ret; |
| } |
| |
| static gboolean |
| gst_cog_scale_get_unit_size (GstBaseTransform * trans, GstCaps * caps, |
| guint * size) |
| { |
| GstVideoFormat format; |
| gint width, height; |
| |
| g_assert (size); |
| |
| if (!gst_video_format_parse_caps (caps, &format, &width, &height)) |
| return FALSE; |
| |
| *size = gst_video_format_get_size (format, width, height); |
| |
| return TRUE; |
| } |
| |
| static void |
| gst_cog_scale_fixate_caps (GstBaseTransform * base, GstPadDirection direction, |
| GstCaps * caps, GstCaps * othercaps) |
| { |
| 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"); |
| |
| /* we have both PAR but they might not be fixated */ |
| if (from_par && to_par) { |
| gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d; |
| gint count = 0, w = 0, h = 0; |
| guint num, den; |
| |
| /* from_par should be fixed */ |
| g_return_if_fail (gst_value_is_fixed (from_par)); |
| |
| from_par_n = gst_value_get_fraction_numerator (from_par); |
| from_par_d = gst_value_get_fraction_denominator (from_par); |
| |
| /* fixate the out PAR */ |
| if (!gst_value_is_fixed (to_par)) { |
| GST_DEBUG_OBJECT (base, "fixating to_par to %dx%d", from_par_n, |
| from_par_d); |
| gst_structure_fixate_field_nearest_fraction (outs, "pixel-aspect-ratio", |
| from_par_n, from_par_d); |
| } |
| |
| to_par_n = gst_value_get_fraction_numerator (to_par); |
| to_par_d = gst_value_get_fraction_denominator (to_par); |
| |
| /* 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; |
| } |
| |
| gst_structure_get_int (ins, "width", &from_w); |
| gst_structure_get_int (ins, "height", &from_h); |
| |
| if (!gst_video_calculate_display_ratio (&num, &den, from_w, from_h, |
| from_par_n, from_par_d, to_par_n, to_par_d)) { |
| GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL), |
| ("Error calculating the output scaled size - integer overflow")); |
| return; |
| } |
| |
| 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 */ |
| |
| /* if one of the output width or height is fixed, we work from there */ |
| if (h) { |
| GST_DEBUG_OBJECT (base, "height is fixed,scaling width"); |
| w = (guint) gst_util_uint64_scale_int (h, num, den); |
| } else if (w) { |
| GST_DEBUG_OBJECT (base, "width is fixed, scaling height"); |
| h = (guint) gst_util_uint64_scale_int (w, den, num); |
| } else { |
| /* none of width or height is fixed, figure out both of them based only on |
| * the input width and height */ |
| /* 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 = (guint) gst_util_uint64_scale_int (h, num, den); |
| } else if (from_w % num == 0) { |
| GST_DEBUG_OBJECT (base, "keeping video width"); |
| w = from_w; |
| h = (guint) gst_util_uint64_scale_int (w, den, num); |
| } else { |
| GST_DEBUG_OBJECT (base, "approximating but keeping video height"); |
| h = from_h; |
| w = (guint) gst_util_uint64_scale_int (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; |
| |
| 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_int (ins, "height", &height)) { |
| if (gst_structure_has_field (outs, "height")) { |
| gst_structure_fixate_field_nearest_int (outs, "height", height); |
| } |
| } |
| } |
| |
| GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps); |
| } |
| |
| #if 0 |
| static gboolean |
| gst_cog_scale_prepare_image (gint format, GstBuffer * buf, |
| VSImage * img, VSImage * img_u, VSImage * img_v) |
| { |
| gboolean res = TRUE; |
| |
| img->pixels = GST_BUFFER_DATA (buf); |
| |
| switch (format) { |
| case GST_VIDEO_FORMAT_I420: |
| case GST_VIDEO_FORMAT_YV12: |
| img_u->pixels = img->pixels + GST_ROUND_UP_2 (img->height) * img->stride; |
| img_u->height = GST_ROUND_UP_2 (img->height) / 2; |
| img_u->width = GST_ROUND_UP_2 (img->width) / 2; |
| img_u->stride = GST_ROUND_UP_4 (img_u->width); |
| memcpy (img_v, img_u, sizeof (*img_v)); |
| img_v->pixels = img_u->pixels + img_u->height * img_u->stride; |
| break; |
| default: |
| break; |
| } |
| return res; |
| } |
| #endif |
| |
| static GstFlowReturn |
| gst_cog_scale_transform (GstBaseTransform * trans, GstBuffer * in, |
| GstBuffer * out) |
| { |
| GstCogScale *videoscale; |
| GstFlowReturn ret = GST_FLOW_OK; |
| CogFrame *outframe; |
| CogFrame *frame; |
| int w, h; |
| int quality; |
| static const int n_vert_taps[11] = { 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4 }; |
| static const int n_horiz_taps[11] = { 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4 }; |
| |
| videoscale = GST_COG_SCALE (trans); |
| |
| GST_OBJECT_LOCK (videoscale); |
| quality = videoscale->quality; |
| GST_OBJECT_UNLOCK (videoscale); |
| |
| frame = gst_cog_buffer_wrap (gst_buffer_ref (in), videoscale->format, |
| videoscale->from_width, videoscale->from_height); |
| outframe = gst_cog_buffer_wrap (gst_buffer_ref (out), videoscale->format, |
| videoscale->to_width, videoscale->to_height); |
| |
| frame = cog_virt_frame_new_unpack (frame); |
| |
| w = videoscale->from_width; |
| h = videoscale->from_height; |
| while (w >= 2 * videoscale->to_width || h >= 2 * videoscale->to_height) { |
| if (w >= 2 * videoscale->to_width) { |
| frame = cog_virt_frame_new_horiz_downsample (frame, 3); |
| w /= 2; |
| } |
| if (h >= 2 * videoscale->to_height) { |
| frame = cog_virt_frame_new_vert_downsample (frame, 4); |
| h /= 2; |
| } |
| } |
| if (w != videoscale->to_width) { |
| frame = cog_virt_frame_new_horiz_resample (frame, videoscale->to_width, |
| n_horiz_taps[quality]); |
| } |
| if (h != videoscale->to_height) { |
| frame = cog_virt_frame_new_vert_resample (frame, videoscale->to_height, |
| n_vert_taps[quality]); |
| } |
| |
| switch (videoscale->format) { |
| case GST_VIDEO_FORMAT_YUY2: |
| frame = cog_virt_frame_new_pack_YUY2 (frame); |
| break; |
| case GST_VIDEO_FORMAT_UYVY: |
| frame = cog_virt_frame_new_pack_UYVY (frame); |
| break; |
| default: |
| break; |
| } |
| |
| cog_virt_frame_render (frame, outframe); |
| cog_frame_unref (frame); |
| cog_frame_unref (outframe); |
| |
| GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes", |
| GST_BUFFER_SIZE (out)); |
| |
| return ret; |
| |
| /* ERRORS */ |
| #if 0 |
| unsupported: |
| { |
| GST_ELEMENT_ERROR (videoscale, STREAM, NOT_IMPLEMENTED, (NULL), |
| ("Unsupported format %d for scaling method %d", |
| videoscale->format, method)); |
| return GST_FLOW_ERROR; |
| } |
| unknown_mode: |
| { |
| GST_ELEMENT_ERROR (videoscale, STREAM, NOT_IMPLEMENTED, (NULL), |
| ("Unknown scaling method %d", videoscale->method)); |
| return GST_FLOW_ERROR; |
| } |
| #endif |
| } |
| |
| static gboolean |
| gst_cog_scale_src_event (GstBaseTransform * trans, GstEvent * event) |
| { |
| GstCogScale *videoscale; |
| gboolean ret; |
| double a; |
| GstStructure *structure; |
| |
| videoscale = GST_COG_SCALE (trans); |
| |
| GST_DEBUG_OBJECT (videoscale, "handling %s event", |
| GST_EVENT_TYPE_NAME (event)); |
| |
| switch (GST_EVENT_TYPE (event)) { |
| case GST_EVENT_NAVIGATION: |
| event = |
| GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event))); |
| |
| 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 * 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); |
| } |
| break; |
| case GST_EVENT_QOS: |
| break; |
| default: |
| break; |
| } |
| |
| ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event); |
| |
| return ret; |
| } |