+++ /dev/null
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * This file:
- * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
- * Copyright (C) 2010 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., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-/**
- * SECTION:element-videoconvert
- * @title: videoconvert
- *
- * Convert video frames between a great variety of video formats.
- *
- * ## Example launch line
- * |[
- * gst-launch-1.0 -v videotestsrc ! video/x-raw,format=YUY2 ! videoconvert ! autovideosink
- * ]|
- * This will output a test video (generated in YUY2 format) in a video
- * window. If the video sink selected does not support YUY2 videoconvert will
- * automatically convert the video to a format understood by the video sink.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gstvideoconvert.h"
-
-#include <gst/video/video.h>
-#include <gst/video/gstvideometa.h>
-#include <gst/video/gstvideopool.h>
-
-#ifdef USE_TBM
-#include <gst/allocators/gsttizenbufferpool.h>
-#endif
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY (videoconvert_debug);
-#define GST_CAT_DEFAULT videoconvert_debug
-GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
-
-static GQuark _colorspace_quark;
-
-#define gst_video_convert_parent_class parent_class
-G_DEFINE_TYPE (GstVideoConvert, gst_video_convert, GST_TYPE_VIDEO_FILTER);
-GST_ELEMENT_REGISTER_DEFINE (videoconvert, "videoconvert",
- GST_RANK_NONE, GST_TYPE_VIDEO_CONVERT);
-
-#define DEFAULT_PROP_DITHER GST_VIDEO_DITHER_BAYER
-#define DEFAULT_PROP_DITHER_QUANTIZATION 1
-#define DEFAULT_PROP_CHROMA_RESAMPLER GST_VIDEO_RESAMPLER_METHOD_LINEAR
-#define DEFAULT_PROP_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
-#define DEFAULT_PROP_ALPHA_VALUE 1.0
-#define DEFAULT_PROP_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
-#define DEFAULT_PROP_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
-#define DEFAULT_PROP_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
-#define DEFAULT_PROP_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
-#define DEFAULT_PROP_N_THREADS 1
-
-enum
-{
- PROP_0,
- PROP_DITHER,
- PROP_DITHER_QUANTIZATION,
- PROP_CHROMA_RESAMPLER,
- PROP_ALPHA_MODE,
- PROP_ALPHA_VALUE,
- PROP_CHROMA_MODE,
- PROP_MATRIX_MODE,
- PROP_GAMMA_MODE,
- PROP_PRIMARIES_MODE,
- PROP_N_THREADS
-};
-
-#define CSP_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ";" \
- GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL) ";" \
- GST_VIDEO_CAPS_MAKE("{ SUYV , SYVY , S420 , ITLV }") ";" \
- GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", "{ SUYV , SYVY , S420 , ITLV }")
-
-#define CSP_VIDEO_SRC_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ";" \
- GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL) ";" \
- GST_VIDEO_CAPS_MAKE("{ SUYV , SYVY , S420 , ITLV , SN12 }") ";" \
- GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", "{ SUYV , SYVY , S420 , ITLV , SN12 }")
-
-static GstStaticPadTemplate gst_video_convert_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (CSP_VIDEO_SRC_CAPS)
- );
-
-static GstStaticPadTemplate gst_video_convert_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (CSP_VIDEO_CAPS)
- );
-
-static void gst_video_convert_set_property (GObject * object,
- guint property_id, const GValue * value, GParamSpec * pspec);
-static void gst_video_convert_get_property (GObject * object,
- guint property_id, GValue * value, GParamSpec * pspec);
-
-static gboolean gst_video_convert_set_info (GstVideoFilter * filter,
- GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
- GstVideoInfo * out_info);
-static GstFlowReturn gst_video_convert_transform_frame (GstVideoFilter * filter,
- GstVideoFrame * in_frame, GstVideoFrame * out_frame);
-
-#ifdef USE_TBM
-static gboolean gst_video_convert_decide_allocation (GstBaseTransform * bsrc,
- GstQuery * query);
-static GstFlowReturn gst_video_convert_prepare_output_buffer (GstBaseTransform * trans,
- GstBuffer *input, GstBuffer **outbuf);
-#endif
-static GstCapsFeatures *features_format_interlaced,
- *features_format_interlaced_sysmem;
-
-/* copies the given caps */
-static GstCaps *
-gst_video_convert_caps_remove_format_info (GstCaps * caps)
-{
- GstStructure *st;
- GstCapsFeatures *f;
- gint i, n;
- GstCaps *res;
-
- res = gst_caps_new_empty ();
-
- n = gst_caps_get_size (caps);
- for (i = 0; i < n; i++) {
- st = gst_caps_get_structure (caps, i);
- f = gst_caps_get_features (caps, i);
-
- /* If this is already expressed by the existing caps
- * skip this structure */
- if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
- continue;
-
- st = gst_structure_copy (st);
- /* Only remove format info for the cases when we can actually convert */
- if (!gst_caps_features_is_any (f)
- && (gst_caps_features_is_equal (f,
- GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
- || gst_caps_features_is_equal (f, features_format_interlaced)
- || gst_caps_features_is_equal (f,
- features_format_interlaced_sysmem))) {
- gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
- NULL);
- }
-
- gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
- }
-
- return res;
-}
-
-/*
- * This is an incomplete matrix of in formats and a score for the preferred output
- * format.
- *
- * out: RGB24 RGB16 ARGB AYUV YUV444 YUV422 YUV420 YUV411 YUV410 PAL GRAY
- * in
- * RGB24 0 2 1 2 2 3 4 5 6 7 8
- * RGB16 1 0 1 2 2 3 4 5 6 7 8
- * ARGB 2 3 0 1 4 5 6 7 8 9 10
- * AYUV 3 4 1 0 2 5 6 7 8 9 10
- * YUV444 2 4 3 1 0 5 6 7 8 9 10
- * YUV422 3 5 4 2 1 0 6 7 8 9 10
- * YUV420 4 6 5 3 2 1 0 7 8 9 10
- * YUV411 4 6 5 3 2 1 7 0 8 9 10
- * YUV410 6 8 7 5 4 3 2 1 0 9 10
- * PAL 1 3 2 6 4 6 7 8 9 0 10
- * GRAY 1 4 3 2 1 5 6 7 8 9 0
- *
- * PAL or GRAY are never preferred, if we can we would convert to PAL instead
- * of GRAY, though
- * less subsampling is preferred and if any, preferably horizontal
- * We would like to keep the alpha, even if we would need to to colorspace conversion
- * or lose depth.
- */
-#define SCORE_FORMAT_CHANGE 1
-#define SCORE_DEPTH_CHANGE 1
-#define SCORE_ALPHA_CHANGE 1
-#define SCORE_CHROMA_W_CHANGE 1
-#define SCORE_CHROMA_H_CHANGE 1
-#define SCORE_PALETTE_CHANGE 1
-
-#define SCORE_COLORSPACE_LOSS 2 /* RGB <-> YUV */
-#define SCORE_DEPTH_LOSS 4 /* change bit depth */
-#define SCORE_ALPHA_LOSS 8 /* lose the alpha channel */
-#define SCORE_CHROMA_W_LOSS 16 /* vertical subsample */
-#define SCORE_CHROMA_H_LOSS 32 /* horizontal subsample */
-#define SCORE_PALETTE_LOSS 64 /* convert to palette format */
-#define SCORE_COLOR_LOSS 128 /* convert to GRAY */
-
-#define COLORSPACE_MASK (GST_VIDEO_FORMAT_FLAG_YUV | \
- GST_VIDEO_FORMAT_FLAG_RGB | GST_VIDEO_FORMAT_FLAG_GRAY)
-#define ALPHA_MASK (GST_VIDEO_FORMAT_FLAG_ALPHA)
-#define PALETTE_MASK (GST_VIDEO_FORMAT_FLAG_PALETTE)
-
-/* calculate how much loss a conversion would be */
-static void
-score_value (GstBaseTransform * base, const GstVideoFormatInfo * in_info,
- const GValue * val, gint * min_loss, const GstVideoFormatInfo ** out_info)
-{
- const gchar *fname;
- const GstVideoFormatInfo *t_info;
- GstVideoFormatFlags in_flags, t_flags;
- gint loss;
-
- fname = g_value_get_string (val);
- t_info = gst_video_format_get_info (gst_video_format_from_string (fname));
- if (!t_info)
- return;
-
- /* accept input format immediately without loss */
- if (in_info == t_info) {
- *min_loss = 0;
- *out_info = t_info;
- return;
- }
-
- loss = SCORE_FORMAT_CHANGE;
-
- in_flags = GST_VIDEO_FORMAT_INFO_FLAGS (in_info);
- in_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
- in_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
- in_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
-
- t_flags = GST_VIDEO_FORMAT_INFO_FLAGS (t_info);
- t_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
- t_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
- t_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
-
- if ((t_flags & PALETTE_MASK) != (in_flags & PALETTE_MASK)) {
- loss += SCORE_PALETTE_CHANGE;
- if (t_flags & PALETTE_MASK)
- loss += SCORE_PALETTE_LOSS;
- }
-
- if ((t_flags & COLORSPACE_MASK) != (in_flags & COLORSPACE_MASK)) {
- loss += SCORE_COLORSPACE_LOSS;
- if (t_flags & GST_VIDEO_FORMAT_FLAG_GRAY)
- loss += SCORE_COLOR_LOSS;
- }
-
- if ((t_flags & ALPHA_MASK) != (in_flags & ALPHA_MASK)) {
- loss += SCORE_ALPHA_CHANGE;
- if (in_flags & ALPHA_MASK)
- loss += SCORE_ALPHA_LOSS;
- }
-
- if ((in_info->h_sub[1]) != (t_info->h_sub[1])) {
- loss += SCORE_CHROMA_H_CHANGE;
- if ((in_info->h_sub[1]) < (t_info->h_sub[1]))
- loss += SCORE_CHROMA_H_LOSS;
- }
- if ((in_info->w_sub[1]) != (t_info->w_sub[1])) {
- loss += SCORE_CHROMA_W_CHANGE;
- if ((in_info->w_sub[1]) < (t_info->w_sub[1]))
- loss += SCORE_CHROMA_W_LOSS;
- }
-
- if ((in_info->bits) != (t_info->bits)) {
- loss += SCORE_DEPTH_CHANGE;
- if ((in_info->bits) > (t_info->bits))
- loss += SCORE_DEPTH_LOSS;
- }
-
- GST_DEBUG_OBJECT (base, "score %s -> %s = %d",
- GST_VIDEO_FORMAT_INFO_NAME (in_info),
- GST_VIDEO_FORMAT_INFO_NAME (t_info), loss);
-
- if (loss < *min_loss) {
- GST_DEBUG_OBJECT (base, "found new best %d", loss);
- *out_info = t_info;
- *min_loss = loss;
- }
-}
-
-static void
-gst_video_convert_fixate_format (GstBaseTransform * base, GstCaps * caps,
- GstCaps * result)
-{
- GstStructure *ins, *outs;
- const gchar *in_format;
- const GstVideoFormatInfo *in_info, *out_info = NULL;
- gint min_loss = G_MAXINT;
- guint i, capslen;
-
- ins = gst_caps_get_structure (caps, 0);
- in_format = gst_structure_get_string (ins, "format");
- if (!in_format)
- return;
-
- GST_DEBUG_OBJECT (base, "source format %s", in_format);
-
- in_info =
- gst_video_format_get_info (gst_video_format_from_string (in_format));
- if (!in_info)
- return;
-
- outs = gst_caps_get_structure (result, 0);
-
- capslen = gst_caps_get_size (result);
- GST_DEBUG_OBJECT (base, "iterate %d structures", capslen);
- for (i = 0; i < capslen; i++) {
- GstStructure *tests;
- const GValue *format;
-
- tests = gst_caps_get_structure (result, i);
- format = gst_structure_get_value (tests, "format");
- /* should not happen */
- if (format == NULL)
- continue;
-
- if (GST_VALUE_HOLDS_LIST (format)) {
- gint j, len;
-
- len = gst_value_list_get_size (format);
- GST_DEBUG_OBJECT (base, "have %d formats", len);
- for (j = 0; j < len; j++) {
- const GValue *val;
-
- val = gst_value_list_get_value (format, j);
- if (G_VALUE_HOLDS_STRING (val)) {
- score_value (base, in_info, val, &min_loss, &out_info);
- if (min_loss == 0)
- break;
- }
- }
- } else if (G_VALUE_HOLDS_STRING (format)) {
- score_value (base, in_info, format, &min_loss, &out_info);
- }
- }
- if (out_info)
- gst_structure_set (outs, "format", G_TYPE_STRING,
- GST_VIDEO_FORMAT_INFO_NAME (out_info), NULL);
-}
-
-static gboolean
-subsampling_unchanged (GstVideoInfo * in_info, GstVideoInfo * out_info)
-{
- gint i;
- const GstVideoFormatInfo *in_format, *out_format;
-
- if (GST_VIDEO_INFO_N_COMPONENTS (in_info) !=
- GST_VIDEO_INFO_N_COMPONENTS (out_info))
- return FALSE;
-
- in_format = in_info->finfo;
- out_format = out_info->finfo;
-
- for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (in_info); i++) {
- if (GST_VIDEO_FORMAT_INFO_W_SUB (in_format,
- i) != GST_VIDEO_FORMAT_INFO_W_SUB (out_format, i))
- return FALSE;
- if (GST_VIDEO_FORMAT_INFO_H_SUB (in_format,
- i) != GST_VIDEO_FORMAT_INFO_H_SUB (out_format, i))
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-transfer_colorimetry_from_input (GstBaseTransform * trans, GstCaps * in_caps,
- GstCaps * out_caps)
-{
- GstStructure *out_caps_s = gst_caps_get_structure (out_caps, 0);
- GstStructure *in_caps_s = gst_caps_get_structure (in_caps, 0);
- gboolean have_colorimetry =
- gst_structure_has_field (out_caps_s, "colorimetry");
- gboolean have_chroma_site =
- gst_structure_has_field (out_caps_s, "chroma-site");
-
- /* If the output already has colorimetry and chroma-site, stop,
- * otherwise try and transfer what we can from the input caps */
- if (have_colorimetry && have_chroma_site)
- return;
-
- {
- GstVideoInfo in_info, out_info;
- const GValue *in_colorimetry =
- gst_structure_get_value (in_caps_s, "colorimetry");
-
- if (!gst_video_info_from_caps (&in_info, in_caps)) {
- GST_WARNING_OBJECT (trans,
- "Failed to convert sink pad caps to video info");
- return;
- }
- if (!gst_video_info_from_caps (&out_info, out_caps)) {
- GST_WARNING_OBJECT (trans,
- "Failed to convert src pad caps to video info");
- return;
- }
-
- if (!have_colorimetry && in_colorimetry != NULL) {
- if ((GST_VIDEO_INFO_IS_YUV (&out_info)
- && GST_VIDEO_INFO_IS_YUV (&in_info))
- || (GST_VIDEO_INFO_IS_RGB (&out_info)
- && GST_VIDEO_INFO_IS_RGB (&in_info))
- || (GST_VIDEO_INFO_IS_GRAY (&out_info)
- && GST_VIDEO_INFO_IS_GRAY (&in_info))) {
- /* Can transfer the colorimetry intact from the input if it has it */
- gst_structure_set_value (out_caps_s, "colorimetry", in_colorimetry);
- } else {
- gchar *colorimetry_str;
-
- /* Changing between YUV/RGB - forward primaries and transfer function, but use
- * default range and matrix.
- * the primaries is used for conversion between RGB and XYZ (CIE 1931 coordinate).
- * the transfer function could be another reference (e.g., HDR)
- */
- out_info.colorimetry.primaries = in_info.colorimetry.primaries;
- out_info.colorimetry.transfer = in_info.colorimetry.transfer;
-
- colorimetry_str =
- gst_video_colorimetry_to_string (&out_info.colorimetry);
- gst_caps_set_simple (out_caps, "colorimetry", G_TYPE_STRING,
- colorimetry_str, NULL);
- g_free (colorimetry_str);
- }
- }
-
- /* Only YUV output needs chroma-site. If the input was also YUV and had the same chroma
- * subsampling, transfer the siting. If the sub-sampling is changing, then the planes get
- * scaled anyway so there's no real reason to prefer the input siting. */
- if (!have_chroma_site && GST_VIDEO_INFO_IS_YUV (&out_info)) {
- if (GST_VIDEO_INFO_IS_YUV (&in_info)) {
- const GValue *in_chroma_site =
- gst_structure_get_value (in_caps_s, "chroma-site");
- if (in_chroma_site != NULL
- && subsampling_unchanged (&in_info, &out_info))
- gst_structure_set_value (out_caps_s, "chroma-site", in_chroma_site);
- }
- }
- }
-}
-
-static GstCaps *
-gst_video_convert_fixate_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
-{
- GstCaps *result;
-
- GST_DEBUG_OBJECT (trans, "trying to fixate othercaps %" GST_PTR_FORMAT
- " based on caps %" GST_PTR_FORMAT, othercaps, caps);
-
- result = gst_caps_intersect (othercaps, caps);
- if (gst_caps_is_empty (result)) {
- gst_caps_unref (result);
- result = othercaps;
- } else {
- gst_caps_unref (othercaps);
- }
-
- GST_DEBUG_OBJECT (trans, "now fixating %" GST_PTR_FORMAT, result);
-
- result = gst_caps_make_writable (result);
- gst_video_convert_fixate_format (trans, caps, result);
-
- /* fixate remaining fields */
- result = gst_caps_fixate (result);
-
- if (direction == GST_PAD_SINK) {
- if (gst_caps_is_subset (caps, result)) {
- gst_caps_replace (&result, caps);
- } else {
- /* Try and preserve input colorimetry / chroma information */
- transfer_colorimetry_from_input (trans, caps, result);
- }
- }
-
- return result;
-}
-
-static gboolean
-gst_video_convert_filter_meta (GstBaseTransform * trans, GstQuery * query,
- GType api, const GstStructure * params)
-{
- /* This element cannot passthrough the crop meta, because it would convert the
- * wrong sub-region of the image, and worst, our output image may not be large
- * enough for the crop to be applied later */
- if (api == GST_VIDEO_CROP_META_API_TYPE)
- return FALSE;
-
- /* propose all other metadata upstream */
- return TRUE;
-}
-
-/* The caps can be transformed into any other caps with format info removed.
- * However, we should prefer passthrough, so if passthrough is possible,
- * put it first in the list. */
-static GstCaps *
-gst_video_convert_transform_caps (GstBaseTransform * btrans,
- GstPadDirection direction, GstCaps * caps, GstCaps * filter)
-{
- GstCaps *tmp, *tmp2;
- GstCaps *result;
-
- /* Get all possible caps that we can transform to */
- tmp = gst_video_convert_caps_remove_format_info (caps);
-
- if (filter) {
- tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (tmp);
- tmp = tmp2;
- }
-
- result = tmp;
-
- GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
- GST_PTR_FORMAT, caps, result);
-
- return result;
-}
-
-static gboolean
-gst_video_convert_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
- GstMeta * meta, GstBuffer * inbuf)
-{
- const GstMetaInfo *info = meta->info;
- gboolean ret;
-
- if (gst_meta_api_type_has_tag (info->api, _colorspace_quark)) {
- /* don't copy colorspace specific metadata, FIXME, we need a MetaTransform
- * for the colorspace metadata. */
- ret = FALSE;
- } else {
- /* copy other metadata */
- ret = TRUE;
- }
- return ret;
-}
-
-static gboolean
-gst_video_convert_set_info (GstVideoFilter * filter,
- GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
- GstVideoInfo * out_info)
-{
- GstVideoConvert *space;
- GstBaseTransformClass *gstbasetransform_class =
- GST_BASE_TRANSFORM_GET_CLASS (filter);
- GstVideoInfo tmp_info;
-
- space = GST_VIDEO_CONVERT_CAST (filter);
-
- if (space->convert) {
- gst_video_converter_free (space->convert);
- space->convert = NULL;
- }
-
- /* these must match */
- if (in_info->width != out_info->width || in_info->height != out_info->height
- || in_info->fps_n != out_info->fps_n || in_info->fps_d != out_info->fps_d)
- goto format_mismatch;
-
- /* if present, these must match too */
- if (in_info->par_n != out_info->par_n || in_info->par_d != out_info->par_d)
- goto format_mismatch;
-
- /* if present, these must match too */
- if (in_info->interlace_mode != out_info->interlace_mode)
- goto format_mismatch;
-
- /* if the only thing different in the caps is the transfer function, and
- * we're converting between equivalent transfer functions, do passthrough */
- tmp_info = *in_info;
- tmp_info.colorimetry.transfer = out_info->colorimetry.transfer;
- if (gst_video_info_is_equal (&tmp_info, out_info)) {
- if (gst_video_transfer_function_is_equivalent (in_info->
- colorimetry.transfer, in_info->finfo->bits,
- out_info->colorimetry.transfer, out_info->finfo->bits)) {
- gstbasetransform_class->passthrough_on_same_caps = FALSE;
- gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
- return TRUE;
- }
- }
- gstbasetransform_class->passthrough_on_same_caps = TRUE;
- gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), FALSE);
-
- space->convert = gst_video_converter_new (in_info, out_info,
- gst_structure_new ("GstVideoConvertConfig",
- GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD,
- space->dither,
- GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, G_TYPE_UINT,
- space->dither_quantization,
- GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, space->chroma_resampler,
- GST_VIDEO_CONVERTER_OPT_ALPHA_MODE,
- GST_TYPE_VIDEO_ALPHA_MODE, space->alpha_mode,
- GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE,
- G_TYPE_DOUBLE, space->alpha_value,
- GST_VIDEO_CONVERTER_OPT_CHROMA_MODE,
- GST_TYPE_VIDEO_CHROMA_MODE, space->chroma_mode,
- GST_VIDEO_CONVERTER_OPT_MATRIX_MODE,
- GST_TYPE_VIDEO_MATRIX_MODE, space->matrix_mode,
- GST_VIDEO_CONVERTER_OPT_GAMMA_MODE,
- GST_TYPE_VIDEO_GAMMA_MODE, space->gamma_mode,
- GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE,
- GST_TYPE_VIDEO_PRIMARIES_MODE, space->primaries_mode,
- GST_VIDEO_CONVERTER_OPT_THREADS, G_TYPE_UINT,
- space->n_threads, NULL));
- if (space->convert == NULL)
- goto no_convert;
-
- GST_DEBUG_OBJECT (filter, "converting format %s -> %s",
- gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
- gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
-
- return TRUE;
-
- /* ERRORS */
-format_mismatch:
- {
- GST_ERROR_OBJECT (space, "input and output formats do not match");
- return FALSE;
- }
-no_convert:
- {
- GST_ERROR_OBJECT (space, "could not create converter");
- return FALSE;
- }
-}
-
-static void
-gst_video_convert_finalize (GObject * obj)
-{
- GstVideoConvert *space = GST_VIDEO_CONVERT (obj);
-
-#ifdef USE_TBM
- if (space->pool) {
- gst_buffer_pool_set_active (space->pool, FALSE);
- gst_object_unref (space->pool);
- space->pool = NULL;
- }
-#endif
-
- if (space->convert) {
- gst_video_converter_free (space->convert);
- }
-
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-static void
-gst_video_convert_class_init (GstVideoConvertClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstElementClass *gstelement_class = (GstElementClass *) klass;
- GstBaseTransformClass *gstbasetransform_class =
- (GstBaseTransformClass *) klass;
- GstVideoFilterClass *gstvideofilter_class = (GstVideoFilterClass *) klass;
-
- gobject_class->set_property = gst_video_convert_set_property;
- gobject_class->get_property = gst_video_convert_get_property;
- gobject_class->finalize = gst_video_convert_finalize;
-
- gst_element_class_add_static_pad_template (gstelement_class,
- &gst_video_convert_src_template);
- gst_element_class_add_static_pad_template (gstelement_class,
- &gst_video_convert_sink_template);
-
- gst_element_class_set_static_metadata (gstelement_class,
- "Colorspace converter", "Filter/Converter/Video",
- "Converts video from one colorspace to another",
- "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
-
- gstbasetransform_class->transform_caps =
- GST_DEBUG_FUNCPTR (gst_video_convert_transform_caps);
- gstbasetransform_class->fixate_caps =
- GST_DEBUG_FUNCPTR (gst_video_convert_fixate_caps);
- gstbasetransform_class->filter_meta =
- GST_DEBUG_FUNCPTR (gst_video_convert_filter_meta);
- gstbasetransform_class->transform_meta =
- GST_DEBUG_FUNCPTR (gst_video_convert_transform_meta);
-
- gstbasetransform_class->passthrough_on_same_caps = TRUE;
-
- gstvideofilter_class->set_info =
- GST_DEBUG_FUNCPTR (gst_video_convert_set_info);
- gstvideofilter_class->transform_frame =
- GST_DEBUG_FUNCPTR (gst_video_convert_transform_frame);
-
-#ifdef USE_TBM
- gstbasetransform_class->decide_allocation = gst_video_convert_decide_allocation;
- gstbasetransform_class->prepare_output_buffer = gst_video_convert_prepare_output_buffer;
-#endif
-
- g_object_class_install_property (gobject_class, PROP_DITHER,
- g_param_spec_enum ("dither", "Dither", "Apply dithering while converting",
- gst_video_dither_method_get_type (), DEFAULT_PROP_DITHER,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_DITHER_QUANTIZATION,
- g_param_spec_uint ("dither-quantization", "Dither Quantize",
- "Quantizer to use", 0, G_MAXUINT, DEFAULT_PROP_DITHER_QUANTIZATION,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_CHROMA_RESAMPLER,
- g_param_spec_enum ("chroma-resampler", "Chroma resampler",
- "Chroma resampler method", gst_video_resampler_method_get_type (),
- DEFAULT_PROP_CHROMA_RESAMPLER,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_ALPHA_MODE,
- g_param_spec_enum ("alpha-mode", "Alpha Mode",
- "Alpha Mode to use", gst_video_alpha_mode_get_type (),
- DEFAULT_PROP_ALPHA_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_ALPHA_VALUE,
- g_param_spec_double ("alpha-value", "Alpha Value",
- "Alpha Value to use", 0.0, 1.0,
- DEFAULT_PROP_ALPHA_VALUE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_CHROMA_MODE,
- g_param_spec_enum ("chroma-mode", "Chroma Mode", "Chroma Resampling Mode",
- gst_video_chroma_mode_get_type (), DEFAULT_PROP_CHROMA_MODE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_MATRIX_MODE,
- g_param_spec_enum ("matrix-mode", "Matrix Mode", "Matrix Conversion Mode",
- gst_video_matrix_mode_get_type (), DEFAULT_PROP_MATRIX_MODE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_GAMMA_MODE,
- g_param_spec_enum ("gamma-mode", "Gamma Mode", "Gamma Conversion Mode",
- gst_video_gamma_mode_get_type (), DEFAULT_PROP_GAMMA_MODE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_PRIMARIES_MODE,
- g_param_spec_enum ("primaries-mode", "Primaries Mode",
- "Primaries Conversion Mode", gst_video_primaries_mode_get_type (),
- DEFAULT_PROP_PRIMARIES_MODE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_N_THREADS,
- g_param_spec_uint ("n-threads", "Threads",
- "Maximum number of threads to use", 0, G_MAXUINT,
- DEFAULT_PROP_N_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_video_convert_init (GstVideoConvert * space)
-{
-#ifdef USE_TBM
- space->pool = NULL;
-#endif
- space->dither = DEFAULT_PROP_DITHER;
- space->dither_quantization = DEFAULT_PROP_DITHER_QUANTIZATION;
- space->chroma_resampler = DEFAULT_PROP_CHROMA_RESAMPLER;
- space->alpha_mode = DEFAULT_PROP_ALPHA_MODE;
- space->alpha_value = DEFAULT_PROP_ALPHA_VALUE;
- space->chroma_mode = DEFAULT_PROP_CHROMA_MODE;
- space->matrix_mode = DEFAULT_PROP_MATRIX_MODE;
- space->gamma_mode = DEFAULT_PROP_GAMMA_MODE;
- space->primaries_mode = DEFAULT_PROP_PRIMARIES_MODE;
- space->n_threads = DEFAULT_PROP_N_THREADS;
-}
-
-void
-gst_video_convert_set_property (GObject * object, guint property_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstVideoConvert *csp;
-
- csp = GST_VIDEO_CONVERT (object);
-
- switch (property_id) {
- case PROP_DITHER:
- csp->dither = g_value_get_enum (value);
- break;
- case PROP_CHROMA_RESAMPLER:
- csp->chroma_resampler = g_value_get_enum (value);
- break;
- case PROP_ALPHA_MODE:
- csp->alpha_mode = g_value_get_enum (value);
- break;
- case PROP_ALPHA_VALUE:
- csp->alpha_value = g_value_get_double (value);
- break;
- case PROP_CHROMA_MODE:
- csp->chroma_mode = g_value_get_enum (value);
- break;
- case PROP_MATRIX_MODE:
- csp->matrix_mode = g_value_get_enum (value);
- break;
- case PROP_GAMMA_MODE:
- csp->gamma_mode = g_value_get_enum (value);
- break;
- case PROP_PRIMARIES_MODE:
- csp->primaries_mode = g_value_get_enum (value);
- break;
- case PROP_DITHER_QUANTIZATION:
- csp->dither_quantization = g_value_get_uint (value);
- break;
- case PROP_N_THREADS:
- csp->n_threads = g_value_get_uint (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-void
-gst_video_convert_get_property (GObject * object, guint property_id,
- GValue * value, GParamSpec * pspec)
-{
- GstVideoConvert *csp;
-
- csp = GST_VIDEO_CONVERT (object);
-
- switch (property_id) {
- case PROP_DITHER:
- g_value_set_enum (value, csp->dither);
- break;
- case PROP_CHROMA_RESAMPLER:
- g_value_set_enum (value, csp->chroma_resampler);
- break;
- case PROP_ALPHA_MODE:
- g_value_set_enum (value, csp->alpha_mode);
- break;
- case PROP_ALPHA_VALUE:
- g_value_set_double (value, csp->alpha_value);
- break;
- case PROP_CHROMA_MODE:
- g_value_set_enum (value, csp->chroma_mode);
- break;
- case PROP_MATRIX_MODE:
- g_value_set_enum (value, csp->matrix_mode);
- break;
- case PROP_GAMMA_MODE:
- g_value_set_enum (value, csp->gamma_mode);
- break;
- case PROP_PRIMARIES_MODE:
- g_value_set_enum (value, csp->primaries_mode);
- break;
- case PROP_DITHER_QUANTIZATION:
- g_value_set_uint (value, csp->dither_quantization);
- break;
- case PROP_N_THREADS:
- g_value_set_uint (value, csp->n_threads);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static GstFlowReturn
-gst_video_convert_transform_frame (GstVideoFilter * filter,
- GstVideoFrame * in_frame, GstVideoFrame * out_frame)
-{
- GstVideoConvert *space;
-
- space = GST_VIDEO_CONVERT_CAST (filter);
-
- GST_CAT_DEBUG_OBJECT (CAT_PERFORMANCE, filter,
- "doing colorspace conversion from %s -> to %s",
- GST_VIDEO_INFO_NAME (&filter->in_info),
- GST_VIDEO_INFO_NAME (&filter->out_info));
-
- gst_video_converter_frame (space->convert, in_frame, out_frame);
-
- return GST_FLOW_OK;
-}
-
-#ifdef USE_TBM
-static gboolean
-gst_video_convert_decide_allocation (GstBaseTransform * trans,
- GstQuery * query)
-{
- GstVideoConvert *vc = NULL;
- GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
- vc = GST_VIDEO_CONVERT_CAST(trans);
-
- if (filter->out_info.finfo->format == GST_VIDEO_FORMAT_SN12 ) {
- guint size;
- GstStructure *config;
- GstCaps *caps = NULL;
- GstVideoInfo vinfo;
- gst_query_parse_allocation (query, &caps, NULL);
- gst_video_info_init (&vinfo);
- gst_video_info_from_caps (&vinfo, caps);
-
- size = vinfo.size;
-
- if (caps) {
- vc->pool = gst_tizen_buffer_pool_new ();
- config = gst_buffer_pool_get_config (vc->pool);
-
- gst_buffer_pool_config_set_params (config, caps, size, 4, 10);
- gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
- gst_buffer_pool_set_config (vc->pool, config);
-
- if (!gst_buffer_pool_set_active (vc->pool, TRUE)) {
- gst_object_unref (vc->pool);
- vc->pool = NULL;
- GST_INFO ("Failed to activate internal pool");
- }
- } else {
- GST_ERROR("Not using our internal pool and copying buffers for downstream");
- return FALSE;
- }
- }
- GST_DEBUG("[%s]Creating Tizen Buffer Pool", __FUNCTION__);
-
- return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans, query);
-}
-
-static GstFlowReturn
-gst_video_convert_prepare_output_buffer (GstBaseTransform * trans,
- GstBuffer *input, GstBuffer **outbuf)
-{
- GstBuffer *buf = NULL;
- GstVideoConvert *vc = NULL;
- GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
-
- vc = GST_VIDEO_CONVERT_CAST (trans);
-
- if (filter->out_info.finfo->format == GST_VIDEO_FORMAT_SN12 ) {
- if (gst_buffer_pool_acquire_buffer (vc->pool, &buf, 0) != GST_FLOW_OK) {
- GST_ERROR("[%s] memory prepare failed.",__FUNCTION__);
- return GST_FLOW_ERROR;
- }
-
- if (input != buf)
- GST_BASE_TRANSFORM_CLASS (parent_class)->copy_metadata (trans, input, buf);
- *outbuf = buf;
-
- return GST_FLOW_OK;
- }
- return GST_BASE_TRANSFORM_CLASS (parent_class)->prepare_output_buffer(trans, input, outbuf);
-}
-#endif
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (videoconvert_debug, "videoconvert", 0,
- "Colorspace Converter");
-
- GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
-
- _colorspace_quark = g_quark_from_static_string ("colorspace");
-
- features_format_interlaced =
- gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL);
- features_format_interlaced_sysmem =
- gst_caps_features_copy (features_format_interlaced);
- gst_caps_features_add (features_format_interlaced_sysmem,
- GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
-
- return GST_ELEMENT_REGISTER (videoconvert, plugin);
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- videoconvert, "Colorspace conversion", plugin_init, VERSION, GST_LICENSE,
- GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
+++ /dev/null
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) 2005-2012 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., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-/**
- * SECTION:element-videoscale
- * @title: videoscale
- * @see_also: videorate, videoconvert
- *
- * 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.
- *
- * 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.
- *
- * ## Example pipelines
- * |[
- * gst-launch-1.0 -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videoconvert ! videoscale ! autovideosink
- * ]|
- * Decode an Ogg/Theora and display the video. If the video sink chosen
- * 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.
- * |[
- * gst-launch-1.0 -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videoconvert ! videoscale ! video/x-raw,width=100 ! autovideosink
- * ]|
- * Decode an Ogg/Theora and display the video with a width of 100.
- *
- */
-
-/*
- * Formulas for PAR, DAR, width and height relations:
- *
- * dar_n w par_n
- * ----- = - * -----
- * dar_d h par_d
- *
- * par_n h dar_n
- * ----- = - * -----
- * par_d w dar_d
- *
- * dar_n par_d
- * w = h * ----- * -----
- * dar_d par_n
- *
- * dar_d par_n
- * h = w * ----- * -----
- * dar_n par_d
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include <math.h>
-
-#include <gst/video/gstvideometa.h>
-#include <gst/video/gstvideopool.h>
-
-#include "gstvideoscale.h"
-
-#define GST_CAT_DEFAULT video_scale_debug
-GST_DEBUG_CATEGORY_STATIC (video_scale_debug);
-GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
-
-#define DEFAULT_PROP_METHOD GST_VIDEO_SCALE_BILINEAR
-#define DEFAULT_PROP_ADD_BORDERS TRUE
-#define DEFAULT_PROP_SHARPNESS 1.0
-#define DEFAULT_PROP_SHARPEN 0.0
-#define DEFAULT_PROP_DITHER FALSE
-#define DEFAULT_PROP_SUBMETHOD 1
-#define DEFAULT_PROP_ENVELOPE 2.0
-#define DEFAULT_PROP_GAMMA_DECODE FALSE
-#define DEFAULT_PROP_N_THREADS 1
-
-enum
-{
- PROP_0,
- PROP_METHOD,
- PROP_ADD_BORDERS,
- PROP_SHARPNESS,
- PROP_SHARPEN,
- PROP_DITHER,
- PROP_SUBMETHOD,
- PROP_ENVELOPE,
- PROP_GAMMA_DECODE,
- PROP_N_THREADS
-};
-
-#undef GST_VIDEO_SIZE_RANGE
-#define GST_VIDEO_SIZE_RANGE "(int) [ 1, 32767]"
-
-/* FIXME: add v210 support
- * FIXME: add v216 support
- * FIXME: add UYVP support
- * FIXME: add A420 support
- * FIXME: add YUV9 support
- * FIXME: add YVU9 support
- * FIXME: add IYU1 support
- * FIXME: add r210 support
- */
-
-#define GST_VIDEO_FORMATS GST_VIDEO_FORMATS_ALL
-
-static GstStaticCaps gst_video_scale_format_caps =
- GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS) ";"
- GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS));
-
-static GQuark _size_quark;
-static GQuark _scale_quark;
-
-#define GST_TYPE_VIDEO_SCALE_METHOD (gst_video_scale_method_get_type())
-static GType
-gst_video_scale_method_get_type (void)
-{
- static GType video_scale_method_type = 0;
-
- static const GEnumValue video_scale_methods[] = {
- {GST_VIDEO_SCALE_NEAREST, "Nearest Neighbour", "nearest-neighbour"},
- {GST_VIDEO_SCALE_BILINEAR, "Bilinear (2-tap)", "bilinear"},
- {GST_VIDEO_SCALE_4TAP, "4-tap Sinc", "4-tap"},
- {GST_VIDEO_SCALE_LANCZOS, "Lanczos", "lanczos"},
- {GST_VIDEO_SCALE_BILINEAR2, "Bilinear (multi-tap)", "bilinear2"},
- {GST_VIDEO_SCALE_SINC, "Sinc (multi-tap)", "sinc"},
- {GST_VIDEO_SCALE_HERMITE, "Hermite (multi-tap)", "hermite"},
- {GST_VIDEO_SCALE_SPLINE, "Spline (multi-tap)", "spline"},
- {GST_VIDEO_SCALE_CATROM, "Catmull-Rom (multi-tap)", "catrom"},
- {GST_VIDEO_SCALE_MITCHELL, "Mitchell (multi-tap)", "mitchell"},
- {0, NULL, NULL},
- };
-
- if (!video_scale_method_type) {
- video_scale_method_type =
- g_enum_register_static ("GstVideoScaleMethod", video_scale_methods);
- }
- return video_scale_method_type;
-}
-
-static GstCaps *
-gst_video_scale_get_capslist (void)
-{
- static GstCaps *caps = NULL;
- static gsize inited = 0;
-
- if (g_once_init_enter (&inited)) {
- caps = gst_static_caps_get (&gst_video_scale_format_caps);
- g_once_init_leave (&inited, 1);
- }
- return caps;
-}
-
-static GstPadTemplate *
-gst_video_scale_src_template_factory (void)
-{
- return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
- gst_video_scale_get_capslist ());
-}
-
-static GstPadTemplate *
-gst_video_scale_sink_template_factory (void)
-{
- return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- gst_video_scale_get_capslist ());
-}
-
-
-static void gst_video_scale_finalize (GstVideoScale * videoscale);
-static gboolean gst_video_scale_src_event (GstBaseTransform * trans,
- GstEvent * event);
-
-/* base transform vmethods */
-static GstCaps *gst_video_scale_transform_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * caps, GstCaps * filter);
-static GstCaps *gst_video_scale_fixate_caps (GstBaseTransform * base,
- GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
-static gboolean gst_video_scale_transform_meta (GstBaseTransform * trans,
- GstBuffer * outbuf, GstMeta * meta, GstBuffer * inbuf);
-
-static gboolean gst_video_scale_set_info (GstVideoFilter * filter,
- GstCaps * in, GstVideoInfo * in_info, GstCaps * out,
- GstVideoInfo * out_info);
-static GstFlowReturn gst_video_scale_transform_frame (GstVideoFilter * filter,
- GstVideoFrame * in, GstVideoFrame * out);
-
-static void gst_video_scale_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_video_scale_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-#define gst_video_scale_parent_class parent_class
-G_DEFINE_TYPE (GstVideoScale, gst_video_scale, GST_TYPE_VIDEO_FILTER);
-GST_ELEMENT_REGISTER_DEFINE (videoscale, "videoscale",
- GST_RANK_NONE, GST_TYPE_VIDEO_SCALE);
-
-static GstCapsFeatures *features_format_interlaced,
- *features_format_interlaced_sysmem;
-
-static void
-gst_video_scale_class_init (GstVideoScaleClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstElementClass *element_class = (GstElementClass *) klass;
- GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
- GstVideoFilterClass *filter_class = (GstVideoFilterClass *) klass;
-
- gobject_class->finalize = (GObjectFinalizeFunc) gst_video_scale_finalize;
- gobject_class->set_property = gst_video_scale_set_property;
- gobject_class->get_property = gst_video_scale_get_property;
-
- g_object_class_install_property (gobject_class, PROP_METHOD,
- g_param_spec_enum ("method", "method", "method",
- GST_TYPE_VIDEO_SCALE_METHOD, DEFAULT_PROP_METHOD,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_ADD_BORDERS,
- g_param_spec_boolean ("add-borders", "Add Borders",
- "Add black borders if necessary to keep the display aspect ratio",
- DEFAULT_PROP_ADD_BORDERS,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_SHARPNESS,
- g_param_spec_double ("sharpness", "Sharpness",
- "Sharpness of filter", 0.5, 1.5, DEFAULT_PROP_SHARPNESS,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_SHARPEN,
- g_param_spec_double ("sharpen", "Sharpen",
- "Sharpening", 0.0, 1.0, DEFAULT_PROP_SHARPEN,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_DITHER,
- g_param_spec_boolean ("dither", "Dither",
- "Add dither (only used for Lanczos method)",
- DEFAULT_PROP_DITHER,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-#if 0
- /* I am hiding submethod for now, since it's poorly named, poorly
- * documented, and will probably just get people into trouble. */
- g_object_class_install_property (gobject_class, PROP_SUBMETHOD,
- g_param_spec_int ("submethod", "submethod",
- "submethod", 0, 3, DEFAULT_PROP_SUBMETHOD,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-#endif
-
- g_object_class_install_property (gobject_class, PROP_ENVELOPE,
- g_param_spec_double ("envelope", "Envelope",
- "Size of filter envelope", 1.0, 5.0, DEFAULT_PROP_ENVELOPE,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_GAMMA_DECODE,
- g_param_spec_boolean ("gamma-decode", "Gamma Decode",
- "Decode gamma before scaling", DEFAULT_PROP_GAMMA_DECODE,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_N_THREADS,
- g_param_spec_uint ("n-threads", "Threads",
- "Maximum number of threads to use", 0, G_MAXUINT,
- DEFAULT_PROP_N_THREADS,
- G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gst_element_class_set_static_metadata (element_class,
- "Video scaler", "Filter/Converter/Video/Scaler",
- "Resizes video", "Wim Taymans <wim.taymans@gmail.com>");
-
- gst_element_class_add_pad_template (element_class,
- gst_video_scale_sink_template_factory ());
- gst_element_class_add_pad_template (element_class,
- gst_video_scale_src_template_factory ());
-
- trans_class->transform_caps =
- GST_DEBUG_FUNCPTR (gst_video_scale_transform_caps);
- trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_scale_fixate_caps);
- trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_scale_src_event);
- trans_class->transform_meta =
- GST_DEBUG_FUNCPTR (gst_video_scale_transform_meta);
-
- filter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_scale_set_info);
- filter_class->transform_frame =
- GST_DEBUG_FUNCPTR (gst_video_scale_transform_frame);
-
- _size_quark = g_quark_from_static_string (GST_META_TAG_VIDEO_SIZE_STR);
- _scale_quark = gst_video_meta_transform_scale_get_quark ();
-
- gst_type_mark_as_plugin_api (GST_TYPE_VIDEO_SCALE_METHOD, 0);
-}
-
-static void
-gst_video_scale_init (GstVideoScale * videoscale)
-{
- videoscale->method = DEFAULT_PROP_METHOD;
- videoscale->add_borders = DEFAULT_PROP_ADD_BORDERS;
- videoscale->submethod = DEFAULT_PROP_SUBMETHOD;
- videoscale->sharpness = DEFAULT_PROP_SHARPNESS;
- videoscale->sharpen = DEFAULT_PROP_SHARPEN;
- videoscale->dither = DEFAULT_PROP_DITHER;
- videoscale->envelope = DEFAULT_PROP_ENVELOPE;
- videoscale->gamma_decode = DEFAULT_PROP_GAMMA_DECODE;
- videoscale->n_threads = DEFAULT_PROP_N_THREADS;
-}
-
-static void
-gst_video_scale_finalize (GstVideoScale * videoscale)
-{
- if (videoscale->convert)
- gst_video_converter_free (videoscale->convert);
-
- G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (videoscale));
-}
-
-static void
-gst_video_scale_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstVideoScale *vscale = GST_VIDEO_SCALE (object);
-
- switch (prop_id) {
- case PROP_METHOD:
- GST_OBJECT_LOCK (vscale);
- vscale->method = g_value_get_enum (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_ADD_BORDERS:
- GST_OBJECT_LOCK (vscale);
- vscale->add_borders = g_value_get_boolean (value);
- GST_OBJECT_UNLOCK (vscale);
- gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM_CAST (vscale));
- break;
- case PROP_SHARPNESS:
- GST_OBJECT_LOCK (vscale);
- vscale->sharpness = g_value_get_double (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_SHARPEN:
- GST_OBJECT_LOCK (vscale);
- vscale->sharpen = g_value_get_double (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_DITHER:
- GST_OBJECT_LOCK (vscale);
- vscale->dither = g_value_get_boolean (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_SUBMETHOD:
- GST_OBJECT_LOCK (vscale);
- vscale->submethod = g_value_get_int (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_ENVELOPE:
- GST_OBJECT_LOCK (vscale);
- vscale->envelope = g_value_get_double (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_GAMMA_DECODE:
- GST_OBJECT_LOCK (vscale);
- vscale->gamma_decode = g_value_get_boolean (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_N_THREADS:
- GST_OBJECT_LOCK (vscale);
- vscale->n_threads = g_value_get_uint (value);
- GST_OBJECT_UNLOCK (vscale);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_video_scale_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstVideoScale *vscale = GST_VIDEO_SCALE (object);
-
- switch (prop_id) {
- case PROP_METHOD:
- GST_OBJECT_LOCK (vscale);
- g_value_set_enum (value, vscale->method);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_ADD_BORDERS:
- GST_OBJECT_LOCK (vscale);
- g_value_set_boolean (value, vscale->add_borders);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_SHARPNESS:
- GST_OBJECT_LOCK (vscale);
- g_value_set_double (value, vscale->sharpness);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_SHARPEN:
- GST_OBJECT_LOCK (vscale);
- g_value_set_double (value, vscale->sharpen);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_DITHER:
- GST_OBJECT_LOCK (vscale);
- g_value_set_boolean (value, vscale->dither);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_SUBMETHOD:
- GST_OBJECT_LOCK (vscale);
- g_value_set_int (value, vscale->submethod);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_ENVELOPE:
- GST_OBJECT_LOCK (vscale);
- g_value_set_double (value, vscale->envelope);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_GAMMA_DECODE:
- GST_OBJECT_LOCK (vscale);
- g_value_set_boolean (value, vscale->gamma_decode);
- GST_OBJECT_UNLOCK (vscale);
- break;
- case PROP_N_THREADS:
- GST_OBJECT_LOCK (vscale);
- g_value_set_uint (value, vscale->n_threads);
- GST_OBJECT_UNLOCK (vscale);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GstCaps *
-gst_video_scale_transform_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * caps, GstCaps * filter)
-{
- GstCaps *ret;
- GstStructure *structure;
- GstCapsFeatures *features;
- gint i, n;
-
- GST_DEBUG_OBJECT (trans,
- "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
- (direction == GST_PAD_SINK) ? "sink" : "src");
-
- ret = gst_caps_new_empty ();
- n = gst_caps_get_size (caps);
- for (i = 0; i < n; i++) {
- structure = gst_caps_get_structure (caps, i);
- features = gst_caps_get_features (caps, i);
-
- /* If this is already expressed by the existing caps
- * skip this structure */
- if (i > 0 && gst_caps_is_subset_structure_full (ret, structure, features))
- continue;
-
- /* make copy */
- structure = gst_structure_copy (structure);
-
- /* If the features are non-sysmem we can only do passthrough */
- if (!gst_caps_features_is_any (features)
- && (gst_caps_features_is_equal (features,
- GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
- || gst_caps_features_is_equal (features, features_format_interlaced)
- || gst_caps_features_is_equal (features,
- features_format_interlaced_sysmem))) {
- 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 (gst_structure_has_field (structure, "pixel-aspect-ratio")) {
- gst_structure_set (structure, "pixel-aspect-ratio",
- GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, NULL);
- }
- }
- gst_caps_append_structure_full (ret, structure,
- gst_caps_features_copy (features));
- }
-
- if (filter) {
- GstCaps *intersection;
-
- intersection =
- gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (ret);
- ret = intersection;
- }
-
- GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
-
- return ret;
-}
-
-static gboolean
-gst_video_scale_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
- GstMeta * meta, GstBuffer * inbuf)
-{
- GstVideoFilter *videofilter = GST_VIDEO_FILTER (trans);
- const GstMetaInfo *info = meta->info;
- const gchar *const *tags;
- const gchar *const *curr = NULL;
- gboolean should_copy = TRUE;
- const gchar *const valid_tags[] = { GST_META_TAG_VIDEO_STR,
- GST_META_TAG_VIDEO_COLORSPACE_STR,
- GST_META_TAG_VIDEO_ORIENTATION_STR,
- GST_META_TAG_VIDEO_SIZE_STR
- };
-
- tags = gst_meta_api_type_get_tags (info->api);
-
- /* No specific tags, we are good to copy */
- if (!tags) {
- return TRUE;
- }
-
- /* We are only changing size, we can preserve other metas tagged as
- orientation and colorspace */
- for (curr = tags; *curr; ++curr) {
-
- /* We dont handle any other tag */
- if (!g_strv_contains (valid_tags, *curr)) {
- should_copy = FALSE;
- break;
- }
- }
-
- /* Cant handle the tags in this meta, let the parent class handle it */
- if (!should_copy) {
- return GST_BASE_TRANSFORM_CLASS (parent_class)->transform_meta (trans,
- outbuf, meta, inbuf);
- }
-
- /* This meta is size sensitive, try to transform it accordingly */
- if (gst_meta_api_type_has_tag (info->api, _size_quark)) {
- GstVideoMetaTransform trans =
- { &videofilter->in_info, &videofilter->out_info };
-
- if (info->transform_func)
- return info->transform_func (outbuf, meta, inbuf, _scale_quark, &trans);
- return FALSE;
- }
-
- /* No need to transform, we can safely copy this meta */
- return TRUE;
-}
-
-static gboolean
-gst_video_scale_set_info (GstVideoFilter * filter, GstCaps * in,
- GstVideoInfo * in_info, GstCaps * out, GstVideoInfo * out_info)
-{
- GstVideoScale *videoscale = GST_VIDEO_SCALE (filter);
- gint from_dar_n, from_dar_d, to_dar_n, to_dar_d;
-
- if (!gst_util_fraction_multiply (in_info->width,
- in_info->height, in_info->par_n, in_info->par_d, &from_dar_n,
- &from_dar_d)) {
- from_dar_n = from_dar_d = -1;
- }
-
- if (!gst_util_fraction_multiply (out_info->width,
- out_info->height, out_info->par_n, out_info->par_d, &to_dar_n,
- &to_dar_d)) {
- to_dar_n = to_dar_d = -1;
- }
-
- videoscale->borders_w = videoscale->borders_h = 0;
- if (to_dar_n != from_dar_n || to_dar_d != from_dar_d) {
- if (videoscale->add_borders) {
- gint n, d, to_h, to_w;
-
- if (from_dar_n != -1 && from_dar_d != -1
- && gst_util_fraction_multiply (from_dar_n, from_dar_d,
- out_info->par_d, out_info->par_n, &n, &d)) {
- to_h = gst_util_uint64_scale_int (out_info->width, d, n);
- if (to_h <= out_info->height) {
- videoscale->borders_h = out_info->height - to_h;
- videoscale->borders_w = 0;
- } else {
- to_w = gst_util_uint64_scale_int (out_info->height, n, d);
- g_assert (to_w <= out_info->width);
- videoscale->borders_h = 0;
- videoscale->borders_w = out_info->width - to_w;
- }
- } else {
- GST_WARNING_OBJECT (videoscale, "Can't calculate borders");
- }
- } else {
- GST_WARNING_OBJECT (videoscale, "Can't keep DAR!");
- }
- }
-
- if (in_info->width == out_info->width && in_info->height == out_info->height
- && videoscale->borders_w == 0 && videoscale->borders_h == 0) {
- gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
- } else {
- GstStructure *options;
- GST_CAT_DEBUG_OBJECT (CAT_PERFORMANCE, filter, "setup videoscaling");
- gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), FALSE);
-
- options = gst_structure_new_empty ("videoscale");
-
- switch (videoscale->method) {
- case GST_VIDEO_SCALE_NEAREST:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_NEAREST,
- NULL);
- break;
- case GST_VIDEO_SCALE_BILINEAR:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_LINEAR,
- GST_VIDEO_RESAMPLER_OPT_MAX_TAPS, G_TYPE_INT, 2, NULL);
- break;
- case GST_VIDEO_SCALE_4TAP:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_SINC,
- GST_VIDEO_RESAMPLER_OPT_MAX_TAPS, G_TYPE_INT, 4, NULL);
- break;
- case GST_VIDEO_SCALE_LANCZOS:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_LANCZOS,
- NULL);
- break;
- case GST_VIDEO_SCALE_BILINEAR2:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_LINEAR,
- NULL);
- break;
- case GST_VIDEO_SCALE_SINC:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_SINC,
- NULL);
- break;
- case GST_VIDEO_SCALE_HERMITE:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_CUBIC,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_B, G_TYPE_DOUBLE, (gdouble) 0.0,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_C, G_TYPE_DOUBLE, (gdouble) 0.0,
- NULL);
- break;
- case GST_VIDEO_SCALE_SPLINE:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_CUBIC,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_B, G_TYPE_DOUBLE, (gdouble) 1.0,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_C, G_TYPE_DOUBLE, (gdouble) 0.0,
- NULL);
- break;
- case GST_VIDEO_SCALE_CATROM:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_CUBIC,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_B, G_TYPE_DOUBLE, (gdouble) 0.0,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_C, G_TYPE_DOUBLE, (gdouble) 0.5,
- NULL);
- break;
- case GST_VIDEO_SCALE_MITCHELL:
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD,
- GST_TYPE_VIDEO_RESAMPLER_METHOD, GST_VIDEO_RESAMPLER_METHOD_CUBIC,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_B, G_TYPE_DOUBLE, (gdouble) 1.0 / 3.0,
- GST_VIDEO_RESAMPLER_OPT_CUBIC_C, G_TYPE_DOUBLE, (gdouble) 1.0 / 3.0,
- NULL);
- break;
- }
- gst_structure_set (options,
- GST_VIDEO_RESAMPLER_OPT_ENVELOPE, G_TYPE_DOUBLE, videoscale->envelope,
- GST_VIDEO_RESAMPLER_OPT_SHARPNESS, G_TYPE_DOUBLE, videoscale->sharpness,
- GST_VIDEO_RESAMPLER_OPT_SHARPEN, G_TYPE_DOUBLE, videoscale->sharpen,
- GST_VIDEO_CONVERTER_OPT_DEST_X, G_TYPE_INT, videoscale->borders_w / 2,
- GST_VIDEO_CONVERTER_OPT_DEST_Y, G_TYPE_INT, videoscale->borders_h / 2,
- GST_VIDEO_CONVERTER_OPT_DEST_WIDTH, G_TYPE_INT,
- out_info->width - videoscale->borders_w,
- GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT, G_TYPE_INT,
- out_info->height - videoscale->borders_h,
- GST_VIDEO_CONVERTER_OPT_MATRIX_MODE, GST_TYPE_VIDEO_MATRIX_MODE,
- GST_VIDEO_MATRIX_MODE_NONE, GST_VIDEO_CONVERTER_OPT_DITHER_METHOD,
- GST_TYPE_VIDEO_DITHER_METHOD, GST_VIDEO_DITHER_NONE,
- GST_VIDEO_CONVERTER_OPT_CHROMA_MODE, GST_TYPE_VIDEO_CHROMA_MODE,
- GST_VIDEO_CHROMA_MODE_NONE,
- GST_VIDEO_CONVERTER_OPT_THREADS, G_TYPE_UINT, videoscale->n_threads,
- NULL);
-
- if (videoscale->gamma_decode) {
- gst_structure_set (options,
- GST_VIDEO_CONVERTER_OPT_GAMMA_MODE, GST_TYPE_VIDEO_GAMMA_MODE,
- GST_VIDEO_GAMMA_MODE_REMAP, NULL);
- }
-
- if (videoscale->convert)
- gst_video_converter_free (videoscale->convert);
- videoscale->convert = gst_video_converter_new (in_info, out_info, options);
- }
-
- GST_DEBUG_OBJECT (videoscale, "from=%dx%d (par=%d/%d dar=%d/%d), size %"
- G_GSIZE_FORMAT " -> to=%dx%d (par=%d/%d dar=%d/%d borders=%d:%d), "
- "size %" G_GSIZE_FORMAT,
- in_info->width, in_info->height, in_info->par_n, in_info->par_d,
- from_dar_n, from_dar_d, in_info->size, out_info->width,
- out_info->height, out_info->par_n, out_info->par_d, to_dar_n, to_dar_d,
- videoscale->borders_w, videoscale->borders_h, out_info->size);
-
- return TRUE;
-}
-
-static GstCaps *
-gst_video_scale_fixate_caps (GstBaseTransform * base, GstPadDirection direction,
- GstCaps * caps, GstCaps * othercaps)
-{
- GstStructure *ins, *outs;
- const GValue *from_par, *to_par;
- GValue fpar = { 0, };
- GValue tpar = { 0, };
-
- othercaps = gst_caps_truncate (othercaps);
- othercaps = gst_caps_make_writable (othercaps);
-
- 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 we're fixating from the sinkpad we always set the PAR and
- * assume that missing PAR on the sinkpad means 1/1 and
- * missing PAR on the srcpad means undefined
- */
- if (direction == GST_PAD_SINK) {
- if (!from_par) {
- g_value_init (&fpar, GST_TYPE_FRACTION);
- gst_value_set_fraction (&fpar, 1, 1);
- from_par = &fpar;
- }
- if (!to_par) {
- g_value_init (&tpar, GST_TYPE_FRACTION_RANGE);
- gst_value_set_fraction_range_full (&tpar, 1, G_MAXINT, G_MAXINT, 1);
- to_par = &tpar;
- }
- } else {
- if (!to_par) {
- g_value_init (&tpar, GST_TYPE_FRACTION);
- gst_value_set_fraction (&tpar, 1, 1);
- to_par = &tpar;
-
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
- NULL);
- }
- if (!from_par) {
- g_value_init (&fpar, GST_TYPE_FRACTION);
- gst_value_set_fraction (&fpar, 1, 1);
- from_par = &fpar;
- }
- }
-
- /* we have both PAR but they might not be fixated */
- {
- gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
- gint w = 0, h = 0;
- gint from_dar_n, from_dar_d;
- gint num, den;
-
- /* from_par should be fixed */
- g_return_val_if_fail (gst_value_is_fixed (from_par), othercaps);
-
- from_par_n = gst_value_get_fraction_numerator (from_par);
- from_par_d = gst_value_get_fraction_denominator (from_par);
-
- gst_structure_get_int (ins, "width", &from_w);
- gst_structure_get_int (ins, "height", &from_h);
-
- gst_structure_get_int (outs, "width", &w);
- gst_structure_get_int (outs, "height", &h);
-
- /* if both width and height are already fixed, we can't do anything
- * about it anymore */
- if (w && h) {
- guint n, d;
-
- GST_DEBUG_OBJECT (base, "dimensions already set to %dx%d, not fixating",
- w, h);
- if (!gst_value_is_fixed (to_par)) {
- if (gst_video_calculate_display_ratio (&n, &d, from_w, from_h,
- from_par_n, from_par_d, w, h)) {
- GST_DEBUG_OBJECT (base, "fixating to_par to %dx%d", n, d);
- if (gst_structure_has_field (outs, "pixel-aspect-ratio"))
- gst_structure_fixate_field_nearest_fraction (outs,
- "pixel-aspect-ratio", n, d);
- else if (n != d)
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- n, d, NULL);
- }
- }
- goto done;
- }
-
- /* Calculate input DAR */
- if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d,
- &from_dar_n, &from_dar_d)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- goto done;
- }
-
- GST_DEBUG_OBJECT (base, "Input DAR is %d/%d", from_dar_n, from_dar_d);
-
- /* If either width or height are fixed there's not much we
- * can do either except choosing a height or width and PAR
- * that matches the DAR as good as possible
- */
- if (h) {
- GstStructure *tmp;
- gint set_w, set_par_n, set_par_d;
-
- GST_DEBUG_OBJECT (base, "height is fixed (%d)", h);
-
- /* If the PAR is fixed too, there's not much to do
- * except choosing the width that is nearest to the
- * width with the same DAR */
- if (gst_value_is_fixed (to_par)) {
- to_par_n = gst_value_get_fraction_numerator (to_par);
- to_par_d = gst_value_get_fraction_denominator (to_par);
-
- GST_DEBUG_OBJECT (base, "PAR is fixed %d/%d", to_par_n, to_par_d);
-
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
- to_par_n, &num, &den)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- goto done;
- }
-
- w = (guint) gst_util_uint64_scale_int_round (h, num, den);
- gst_structure_fixate_field_nearest_int (outs, "width", w);
-
- goto done;
- }
-
- /* The PAR is not fixed and it's quite likely that we can set
- * an arbitrary PAR. */
-
- /* Check if we can keep the input width */
- tmp = gst_structure_copy (outs);
- gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
- gst_structure_get_int (tmp, "width", &set_w);
-
- /* Might have failed but try to keep the DAR nonetheless by
- * adjusting the PAR */
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, h, set_w,
- &to_par_n, &to_par_d)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- gst_structure_free (tmp);
- goto done;
- }
-
- if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
- gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
- gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
- to_par_n, to_par_d);
- gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
- &set_par_d);
- gst_structure_free (tmp);
-
- /* Check if the adjusted PAR is accepted */
- if (set_par_n == to_par_n && set_par_d == to_par_d) {
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "width", G_TYPE_INT, set_w,
- "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
- NULL);
- goto done;
- }
-
- /* Otherwise scale the width to the new PAR and check if the
- * adjusted with is accepted. If all that fails we can't keep
- * the DAR */
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
- set_par_n, &num, &den)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- goto done;
- }
-
- w = (guint) gst_util_uint64_scale_int_round (h, num, den);
- gst_structure_fixate_field_nearest_int (outs, "width", w);
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- set_par_n, set_par_d, NULL);
-
- goto done;
- } else if (w) {
- GstStructure *tmp;
- gint set_h, set_par_n, set_par_d;
-
- GST_DEBUG_OBJECT (base, "width is fixed (%d)", w);
-
- /* If the PAR is fixed too, there's not much to do
- * except choosing the height that is nearest to the
- * height with the same DAR */
- if (gst_value_is_fixed (to_par)) {
- to_par_n = gst_value_get_fraction_numerator (to_par);
- to_par_d = gst_value_get_fraction_denominator (to_par);
-
- GST_DEBUG_OBJECT (base, "PAR is fixed %d/%d", to_par_n, to_par_d);
-
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
- to_par_n, &num, &den)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- goto done;
- }
-
- h = (guint) gst_util_uint64_scale_int_round (w, den, num);
- gst_structure_fixate_field_nearest_int (outs, "height", h);
-
- goto done;
- }
-
- /* The PAR is not fixed and it's quite likely that we can set
- * an arbitrary PAR. */
-
- /* Check if we can keep the input height */
- tmp = gst_structure_copy (outs);
- gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
- gst_structure_get_int (tmp, "height", &set_h);
-
- /* Might have failed but try to keep the DAR nonetheless by
- * adjusting the PAR */
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, w,
- &to_par_n, &to_par_d)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- gst_structure_free (tmp);
- goto done;
- }
- if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
- gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
- gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
- to_par_n, to_par_d);
- gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
- &set_par_d);
- gst_structure_free (tmp);
-
- /* Check if the adjusted PAR is accepted */
- if (set_par_n == to_par_n && set_par_d == to_par_d) {
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "height", G_TYPE_INT, set_h,
- "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
- NULL);
- goto done;
- }
-
- /* Otherwise scale the height to the new PAR and check if the
- * adjusted with is accepted. If all that fails we can't keep
- * the DAR */
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
- set_par_n, &num, &den)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- goto done;
- }
-
- h = (guint) gst_util_uint64_scale_int_round (w, den, num);
- gst_structure_fixate_field_nearest_int (outs, "height", h);
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- set_par_n, set_par_d, NULL);
-
- goto done;
- } else if (gst_value_is_fixed (to_par)) {
- GstStructure *tmp;
- gint set_h, set_w, f_h, f_w;
-
- to_par_n = gst_value_get_fraction_numerator (to_par);
- to_par_d = gst_value_get_fraction_denominator (to_par);
-
- /* Calculate scale factor for the PAR change */
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n,
- to_par_d, &num, &den)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- goto done;
- }
-
- /* Try to keep the input height (because of interlacing) */
- tmp = gst_structure_copy (outs);
- gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
- gst_structure_get_int (tmp, "height", &set_h);
-
- /* This might have failed but try to scale the width
- * to keep the DAR nonetheless */
- w = (guint) gst_util_uint64_scale_int_round (set_h, num, den);
- gst_structure_fixate_field_nearest_int (tmp, "width", w);
- gst_structure_get_int (tmp, "width", &set_w);
- gst_structure_free (tmp);
-
- /* We kept the DAR and the height is nearest to the original height */
- if (set_w == w) {
- gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
- G_TYPE_INT, set_h, NULL);
- goto done;
- }
-
- f_h = set_h;
- f_w = set_w;
-
- /* If the former failed, try to keep the input width at least */
- tmp = gst_structure_copy (outs);
- gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
- gst_structure_get_int (tmp, "width", &set_w);
-
- /* This might have failed but try to scale the width
- * to keep the DAR nonetheless */
- h = (guint) gst_util_uint64_scale_int_round (set_w, den, num);
- gst_structure_fixate_field_nearest_int (tmp, "height", h);
- gst_structure_get_int (tmp, "height", &set_h);
- gst_structure_free (tmp);
-
- /* We kept the DAR and the width is nearest to the original width */
- if (set_h == h) {
- gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
- G_TYPE_INT, set_h, NULL);
- goto done;
- }
-
- /* If all this failed, keep the dimensions with the DAR that was closest
- * to the correct DAR. This changes the DAR but there's not much else to
- * do here.
- */
- if (set_w * ABS (set_h - h) < ABS (f_w - w) * f_h) {
- f_h = set_h;
- f_w = set_w;
- }
- gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT,
- f_h, NULL);
- goto done;
- } else {
- GstStructure *tmp;
- gint set_h, set_w, set_par_n, set_par_d, tmp2;
-
- /* width, height and PAR are not fixed but passthrough is not possible */
-
- /* First try to keep the height and width as good as possible
- * and scale PAR */
- tmp = gst_structure_copy (outs);
- gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
- gst_structure_get_int (tmp, "height", &set_h);
- gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
- gst_structure_get_int (tmp, "width", &set_w);
-
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w,
- &to_par_n, &to_par_d)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- gst_structure_free (tmp);
- goto done;
- }
-
- if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
- gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
- gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
- to_par_n, to_par_d);
- gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
- &set_par_d);
- gst_structure_free (tmp);
-
- if (set_par_n == to_par_n && set_par_d == to_par_d) {
- gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
- G_TYPE_INT, set_h, NULL);
-
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- set_par_n, set_par_d, NULL);
- goto done;
- }
-
- /* Otherwise try to scale width to keep the DAR with the set
- * PAR and height */
- if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
- set_par_n, &num, &den)) {
- GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL),
- ("Error calculating the output scaled size - integer overflow"));
- goto done;
- }
-
- w = (guint) gst_util_uint64_scale_int_round (set_h, num, den);
- tmp = gst_structure_copy (outs);
- gst_structure_fixate_field_nearest_int (tmp, "width", w);
- gst_structure_get_int (tmp, "width", &tmp2);
- gst_structure_free (tmp);
-
- if (tmp2 == w) {
- gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height",
- G_TYPE_INT, set_h, NULL);
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- set_par_n, set_par_d, NULL);
- goto done;
- }
-
- /* ... or try the same with the height */
- h = (guint) gst_util_uint64_scale_int_round (set_w, den, num);
- tmp = gst_structure_copy (outs);
- gst_structure_fixate_field_nearest_int (tmp, "height", h);
- gst_structure_get_int (tmp, "height", &tmp2);
- gst_structure_free (tmp);
-
- if (tmp2 == h) {
- gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
- G_TYPE_INT, tmp2, NULL);
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- set_par_n, set_par_d, NULL);
- goto done;
- }
-
- /* If all fails we can't keep the DAR and take the nearest values
- * for everything from the first try */
- gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
- G_TYPE_INT, set_h, NULL);
- if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
- set_par_n != set_par_d)
- gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- set_par_n, set_par_d, NULL);
- }
- }
-
-done:
- othercaps = gst_caps_fixate (othercaps);
-
- GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
-
- if (from_par == &fpar)
- g_value_unset (&fpar);
- if (to_par == &tpar)
- g_value_unset (&tpar);
-
- return othercaps;
-}
-
-#define GET_LINE(frame, line) \
- (gpointer)(((guint8*)(GST_VIDEO_FRAME_PLANE_DATA (frame, 0))) + \
- GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) * (line))
-
-static GstFlowReturn
-gst_video_scale_transform_frame (GstVideoFilter * filter,
- GstVideoFrame * in_frame, GstVideoFrame * out_frame)
-{
- GstVideoScale *videoscale = GST_VIDEO_SCALE_CAST (filter);
- GstFlowReturn ret = GST_FLOW_OK;
-
- GST_CAT_DEBUG_OBJECT (CAT_PERFORMANCE, filter, "doing video scaling");
-
- gst_video_converter_frame (videoscale->convert, in_frame, out_frame);
-
- return ret;
-}
-
-static gboolean
-gst_video_scale_src_event (GstBaseTransform * trans, GstEvent * event)
-{
- GstVideoScale *videoscale = GST_VIDEO_SCALE_CAST (trans);
- GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
- gboolean ret;
- gdouble a;
- GstStructure *structure;
-
- GST_DEBUG_OBJECT (videoscale, "handling %s event",
- GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NAVIGATION:
- if (filter->in_info.width != filter->out_info.width ||
- filter->in_info.height != filter->out_info.height) {
- 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 * filter->in_info.width / filter->out_info.width, NULL);
- }
- if (gst_structure_get_double (structure, "pointer_y", &a)) {
- gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
- a * filter->in_info.height / filter->out_info.height, NULL);
- }
- }
- break;
- default:
- break;
- }
-
- ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
-
- return ret;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- features_format_interlaced =
- gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL);
- features_format_interlaced_sysmem =
- gst_caps_features_copy (features_format_interlaced);
- gst_caps_features_add (features_format_interlaced_sysmem,
- GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
-
- GST_DEBUG_CATEGORY_INIT (video_scale_debug, "videoscale", 0,
- "videoscale element");
- GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
-
- return GST_ELEMENT_REGISTER (videoscale, plugin);
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- videoscale,
- "Resizes video", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
- GST_PACKAGE_ORIGIN)