Blame gst/videoconvert/gstvideoconvert.c

Packit 971217
/* GStreamer
Packit 971217
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
Packit 971217
 * This file:
Packit 971217
 * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
Packit 971217
 * Copyright (C) 2010 David Schleef <ds@schleef.org>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:element-videoconvert
Packit 971217
 * @title: videoconvert
Packit 971217
 *
Packit 971217
 * Convert video frames between a great variety of video formats.
Packit 971217
 *
Packit 971217
 * ## Example launch line
Packit 971217
 * |[
Packit 971217
 * gst-launch-1.0 -v videotestsrc ! video/x-raw,format=YUY2 ! videoconvert ! autovideosink
Packit 971217
 * ]|
Packit 971217
 *  This will output a test video (generated in YUY2 format) in a video
Packit 971217
 * window. If the video sink selected does not support YUY2 videoconvert will
Packit 971217
 * automatically convert the video to a format understood by the video sink.
Packit 971217
 *
Packit 971217
 */
Packit 971217
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#  include "config.h"
Packit 971217
#endif
Packit 971217
Packit 971217
#include "gstvideoconvert.h"
Packit 971217
Packit 971217
#include <gst/video/video.h>
Packit 971217
#include <gst/video/gstvideometa.h>
Packit 971217
#include <gst/video/gstvideopool.h>
Packit 971217
Packit 971217
#include <string.h>
Packit 971217
Packit 971217
GST_DEBUG_CATEGORY (videoconvert_debug);
Packit 971217
#define GST_CAT_DEFAULT videoconvert_debug
Packit 971217
GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
Packit 971217
Packit 971217
GType gst_video_convert_get_type (void);
Packit 971217
Packit 971217
static GQuark _colorspace_quark;
Packit 971217
Packit 971217
#define gst_video_convert_parent_class parent_class
Packit 971217
G_DEFINE_TYPE (GstVideoConvert, gst_video_convert, GST_TYPE_VIDEO_FILTER);
Packit 971217
Packit 971217
#define DEFAULT_PROP_DITHER      GST_VIDEO_DITHER_BAYER
Packit 971217
#define DEFAULT_PROP_DITHER_QUANTIZATION 1
Packit 971217
#define DEFAULT_PROP_CHROMA_RESAMPLER	GST_VIDEO_RESAMPLER_METHOD_LINEAR
Packit 971217
#define DEFAULT_PROP_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
Packit 971217
#define DEFAULT_PROP_ALPHA_VALUE 1.0
Packit 971217
#define DEFAULT_PROP_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
Packit 971217
#define DEFAULT_PROP_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
Packit 971217
#define DEFAULT_PROP_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
Packit 971217
#define DEFAULT_PROP_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
Packit 971217
#define DEFAULT_PROP_N_THREADS 1
Packit 971217
Packit 971217
enum
Packit 971217
{
Packit 971217
  PROP_0,
Packit 971217
  PROP_DITHER,
Packit 971217
  PROP_DITHER_QUANTIZATION,
Packit 971217
  PROP_CHROMA_RESAMPLER,
Packit 971217
  PROP_ALPHA_MODE,
Packit 971217
  PROP_ALPHA_VALUE,
Packit 971217
  PROP_CHROMA_MODE,
Packit 971217
  PROP_MATRIX_MODE,
Packit 971217
  PROP_GAMMA_MODE,
Packit 971217
  PROP_PRIMARIES_MODE,
Packit 971217
  PROP_N_THREADS
Packit 971217
};
Packit 971217
Packit 971217
#define CSP_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ";" \
Packit 971217
    GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL)
Packit 971217
Packit 971217
static GstStaticPadTemplate gst_video_convert_src_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("src",
Packit 971217
    GST_PAD_SRC,
Packit 971217
    GST_PAD_ALWAYS,
Packit 971217
    GST_STATIC_CAPS (CSP_VIDEO_CAPS)
Packit 971217
    );
Packit 971217
Packit 971217
static GstStaticPadTemplate gst_video_convert_sink_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("sink",
Packit 971217
    GST_PAD_SINK,
Packit 971217
    GST_PAD_ALWAYS,
Packit 971217
    GST_STATIC_CAPS (CSP_VIDEO_CAPS)
Packit 971217
    );
Packit 971217
Packit 971217
static void gst_video_convert_set_property (GObject * object,
Packit 971217
    guint property_id, const GValue * value, GParamSpec * pspec);
Packit 971217
static void gst_video_convert_get_property (GObject * object,
Packit 971217
    guint property_id, GValue * value, GParamSpec * pspec);
Packit 971217
Packit 971217
static gboolean gst_video_convert_set_info (GstVideoFilter * filter,
Packit 971217
    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
Packit 971217
    GstVideoInfo * out_info);
Packit 971217
static GstFlowReturn gst_video_convert_transform_frame (GstVideoFilter * filter,
Packit 971217
    GstVideoFrame * in_frame, GstVideoFrame * out_frame);
Packit 971217
Packit 971217
/* copies the given caps */
Packit 971217
static GstCaps *
Packit 971217
gst_video_convert_caps_remove_format_info (GstCaps * caps)
Packit 971217
{
Packit 971217
  GstStructure *st;
Packit 971217
  GstCapsFeatures *f;
Packit 971217
  gint i, n;
Packit 971217
  GstCaps *res;
Packit 971217
Packit 971217
  res = gst_caps_new_empty ();
Packit 971217
Packit 971217
  n = gst_caps_get_size (caps);
Packit 971217
  for (i = 0; i < n; i++) {
Packit 971217
    st = gst_caps_get_structure (caps, i);
Packit 971217
    f = gst_caps_get_features (caps, i);
Packit 971217
Packit 971217
    /* If this is already expressed by the existing caps
Packit 971217
     * skip this structure */
Packit 971217
    if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
Packit 971217
      continue;
Packit 971217
Packit 971217
    st = gst_structure_copy (st);
Packit 971217
    /* Only remove format info for the cases when we can actually convert */
Packit 971217
    if (!gst_caps_features_is_any (f)
Packit 971217
        && gst_caps_features_is_equal (f,
Packit 971217
            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))
Packit 971217
      gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
Packit 971217
          NULL);
Packit 971217
Packit 971217
    gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
Packit 971217
  }
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/*
Packit 971217
 * This is an incomplete matrix of in formats and a score for the prefered output
Packit 971217
 * format.
Packit 971217
 *
Packit 971217
 *         out: RGB24   RGB16  ARGB  AYUV  YUV444  YUV422 YUV420 YUV411 YUV410  PAL  GRAY
Packit 971217
 *  in
Packit 971217
 * RGB24          0      2       1     2     2       3      4      5      6      7    8
Packit 971217
 * RGB16          1      0       1     2     2       3      4      5      6      7    8
Packit 971217
 * ARGB           2      3       0     1     4       5      6      7      8      9    10
Packit 971217
 * AYUV           3      4       1     0     2       5      6      7      8      9    10
Packit 971217
 * YUV444         2      4       3     1     0       5      6      7      8      9    10
Packit 971217
 * YUV422         3      5       4     2     1       0      6      7      8      9    10
Packit 971217
 * YUV420         4      6       5     3     2       1      0      7      8      9    10
Packit 971217
 * YUV411         4      6       5     3     2       1      7      0      8      9    10
Packit 971217
 * YUV410         6      8       7     5     4       3      2      1      0      9    10
Packit 971217
 * PAL            1      3       2     6     4       6      7      8      9      0    10
Packit 971217
 * GRAY           1      4       3     2     1       5      6      7      8      9    0
Packit 971217
 *
Packit 971217
 * PAL or GRAY are never prefered, if we can we would convert to PAL instead
Packit 971217
 * of GRAY, though
Packit 971217
 * less subsampling is prefered and if any, preferably horizontal
Packit 971217
 * We would like to keep the alpha, even if we would need to to colorspace conversion
Packit 971217
 * or lose depth.
Packit 971217
 */
Packit 971217
#define SCORE_FORMAT_CHANGE       1
Packit 971217
#define SCORE_DEPTH_CHANGE        1
Packit 971217
#define SCORE_ALPHA_CHANGE        1
Packit 971217
#define SCORE_CHROMA_W_CHANGE     1
Packit 971217
#define SCORE_CHROMA_H_CHANGE     1
Packit 971217
#define SCORE_PALETTE_CHANGE      1
Packit 971217
Packit 971217
#define SCORE_COLORSPACE_LOSS     2     /* RGB <-> YUV */
Packit 971217
#define SCORE_DEPTH_LOSS          4     /* change bit depth */
Packit 971217
#define SCORE_ALPHA_LOSS          8     /* lose the alpha channel */
Packit 971217
#define SCORE_CHROMA_W_LOSS      16     /* vertical subsample */
Packit 971217
#define SCORE_CHROMA_H_LOSS      32     /* horizontal subsample */
Packit 971217
#define SCORE_PALETTE_LOSS       64     /* convert to palette format */
Packit 971217
#define SCORE_COLOR_LOSS        128     /* convert to GRAY */
Packit 971217
Packit 971217
#define COLORSPACE_MASK (GST_VIDEO_FORMAT_FLAG_YUV | \
Packit 971217
                         GST_VIDEO_FORMAT_FLAG_RGB | GST_VIDEO_FORMAT_FLAG_GRAY)
Packit 971217
#define ALPHA_MASK      (GST_VIDEO_FORMAT_FLAG_ALPHA)
Packit 971217
#define PALETTE_MASK    (GST_VIDEO_FORMAT_FLAG_PALETTE)
Packit 971217
Packit 971217
/* calculate how much loss a conversion would be */
Packit 971217
static void
Packit 971217
score_value (GstBaseTransform * base, const GstVideoFormatInfo * in_info,
Packit 971217
    const GValue * val, gint * min_loss, const GstVideoFormatInfo ** out_info)
Packit 971217
{
Packit 971217
  const gchar *fname;
Packit 971217
  const GstVideoFormatInfo *t_info;
Packit 971217
  GstVideoFormatFlags in_flags, t_flags;
Packit 971217
  gint loss;
Packit 971217
Packit 971217
  fname = g_value_get_string (val);
Packit 971217
  t_info = gst_video_format_get_info (gst_video_format_from_string (fname));
Packit 971217
  if (!t_info)
Packit 971217
    return;
Packit 971217
Packit 971217
  /* accept input format immediately without loss */
Packit 971217
  if (in_info == t_info) {
Packit 971217
    *min_loss = 0;
Packit 971217
    *out_info = t_info;
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  loss = SCORE_FORMAT_CHANGE;
Packit 971217
Packit 971217
  in_flags = GST_VIDEO_FORMAT_INFO_FLAGS (in_info);
Packit 971217
  in_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
Packit 971217
  in_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
Packit 971217
  in_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
Packit 971217
Packit 971217
  t_flags = GST_VIDEO_FORMAT_INFO_FLAGS (t_info);
Packit 971217
  t_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
Packit 971217
  t_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
Packit 971217
  t_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
Packit 971217
Packit 971217
  if ((t_flags & PALETTE_MASK) != (in_flags & PALETTE_MASK)) {
Packit 971217
    loss += SCORE_PALETTE_CHANGE;
Packit 971217
    if (t_flags & PALETTE_MASK)
Packit 971217
      loss += SCORE_PALETTE_LOSS;
Packit 971217
  }
Packit 971217
Packit 971217
  if ((t_flags & COLORSPACE_MASK) != (in_flags & COLORSPACE_MASK)) {
Packit 971217
    loss += SCORE_COLORSPACE_LOSS;
Packit 971217
    if (t_flags & GST_VIDEO_FORMAT_FLAG_GRAY)
Packit 971217
      loss += SCORE_COLOR_LOSS;
Packit 971217
  }
Packit 971217
Packit 971217
  if ((t_flags & ALPHA_MASK) != (in_flags & ALPHA_MASK)) {
Packit 971217
    loss += SCORE_ALPHA_CHANGE;
Packit 971217
    if (in_flags & ALPHA_MASK)
Packit 971217
      loss += SCORE_ALPHA_LOSS;
Packit 971217
  }
Packit 971217
Packit 971217
  if ((in_info->h_sub[1]) != (t_info->h_sub[1])) {
Packit 971217
    loss += SCORE_CHROMA_H_CHANGE;
Packit 971217
    if ((in_info->h_sub[1]) < (t_info->h_sub[1]))
Packit 971217
      loss += SCORE_CHROMA_H_LOSS;
Packit 971217
  }
Packit 971217
  if ((in_info->w_sub[1]) != (t_info->w_sub[1])) {
Packit 971217
    loss += SCORE_CHROMA_W_CHANGE;
Packit 971217
    if ((in_info->w_sub[1]) < (t_info->w_sub[1]))
Packit 971217
      loss += SCORE_CHROMA_W_LOSS;
Packit 971217
  }
Packit 971217
Packit 971217
  if ((in_info->bits) != (t_info->bits)) {
Packit 971217
    loss += SCORE_DEPTH_CHANGE;
Packit 971217
    if ((in_info->bits) > (t_info->bits))
Packit 971217
      loss += SCORE_DEPTH_LOSS;
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (base, "score %s -> %s = %d",
Packit 971217
      GST_VIDEO_FORMAT_INFO_NAME (in_info),
Packit 971217
      GST_VIDEO_FORMAT_INFO_NAME (t_info), loss);
Packit 971217
Packit 971217
  if (loss < *min_loss) {
Packit 971217
    GST_DEBUG_OBJECT (base, "found new best %d", loss);
Packit 971217
    *out_info = t_info;
Packit 971217
    *min_loss = loss;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_video_convert_fixate_format (GstBaseTransform * base, GstCaps * caps,
Packit 971217
    GstCaps * result)
Packit 971217
{
Packit 971217
  GstStructure *ins, *outs;
Packit 971217
  const gchar *in_format;
Packit 971217
  const GstVideoFormatInfo *in_info, *out_info = NULL;
Packit 971217
  gint min_loss = G_MAXINT;
Packit 971217
  guint i, capslen;
Packit 971217
Packit 971217
  ins = gst_caps_get_structure (caps, 0);
Packit 971217
  in_format = gst_structure_get_string (ins, "format");
Packit 971217
  if (!in_format)
Packit 971217
    return;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (base, "source format %s", in_format);
Packit 971217
Packit 971217
  in_info =
Packit 971217
      gst_video_format_get_info (gst_video_format_from_string (in_format));
Packit 971217
  if (!in_info)
Packit 971217
    return;
Packit 971217
Packit 971217
  outs = gst_caps_get_structure (result, 0);
Packit 971217
Packit 971217
  capslen = gst_caps_get_size (result);
Packit 971217
  GST_DEBUG_OBJECT (base, "iterate %d structures", capslen);
Packit 971217
  for (i = 0; i < capslen; i++) {
Packit 971217
    GstStructure *tests;
Packit 971217
    const GValue *format;
Packit 971217
Packit 971217
    tests = gst_caps_get_structure (result, i);
Packit 971217
    format = gst_structure_get_value (tests, "format");
Packit 971217
    /* should not happen */
Packit 971217
    if (format == NULL)
Packit 971217
      continue;
Packit 971217
Packit 971217
    if (GST_VALUE_HOLDS_LIST (format)) {
Packit 971217
      gint j, len;
Packit 971217
Packit 971217
      len = gst_value_list_get_size (format);
Packit 971217
      GST_DEBUG_OBJECT (base, "have %d formats", len);
Packit 971217
      for (j = 0; j < len; j++) {
Packit 971217
        const GValue *val;
Packit 971217
Packit 971217
        val = gst_value_list_get_value (format, j);
Packit 971217
        if (G_VALUE_HOLDS_STRING (val)) {
Packit 971217
          score_value (base, in_info, val, &min_loss, &out_info);
Packit 971217
          if (min_loss == 0)
Packit 971217
            break;
Packit 971217
        }
Packit 971217
      }
Packit 971217
    } else if (G_VALUE_HOLDS_STRING (format)) {
Packit 971217
      score_value (base, in_info, format, &min_loss, &out_info);
Packit 971217
    }
Packit 971217
  }
Packit 971217
  if (out_info)
Packit 971217
    gst_structure_set (outs, "format", G_TYPE_STRING,
Packit 971217
        GST_VIDEO_FORMAT_INFO_NAME (out_info), NULL);
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
static GstCaps *
Packit 971217
gst_video_convert_fixate_caps (GstBaseTransform * trans,
Packit 971217
    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
Packit 971217
{
Packit 971217
  GstCaps *result;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (trans, "trying to fixate othercaps %" GST_PTR_FORMAT
Packit 971217
      " based on caps %" GST_PTR_FORMAT, othercaps, caps);
Packit 971217
Packit 971217
  result = gst_caps_intersect (othercaps, caps);
Packit 971217
  if (gst_caps_is_empty (result)) {
Packit 971217
    gst_caps_unref (result);
Packit 971217
    result = othercaps;
Packit 971217
  } else {
Packit 971217
    gst_caps_unref (othercaps);
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (trans, "now fixating %" GST_PTR_FORMAT, result);
Packit 971217
Packit 971217
  result = gst_caps_make_writable (result);
Packit 971217
  gst_video_convert_fixate_format (trans, caps, result);
Packit 971217
Packit 971217
  /* fixate remaining fields */
Packit 971217
  result = gst_caps_fixate (result);
Packit 971217
Packit 971217
  if (direction == GST_PAD_SINK) {
Packit 971217
    if (gst_caps_is_subset (caps, result)) {
Packit 971217
      gst_caps_replace (&result, caps);
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_video_convert_filter_meta (GstBaseTransform * trans, GstQuery * query,
Packit 971217
    GType api, const GstStructure * params)
Packit 971217
{
Packit 971217
  /* This element cannot passthrough the crop meta, because it would convert the
Packit 971217
   * wrong sub-region of the image, and worst, our output image may not be large
Packit 971217
   * enough for the crop to be applied later */
Packit 971217
  if (api == GST_VIDEO_CROP_META_API_TYPE)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  /* propose all other metadata upstream */
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/* The caps can be transformed into any other caps with format info removed.
Packit 971217
 * However, we should prefer passthrough, so if passthrough is possible,
Packit 971217
 * put it first in the list. */
Packit 971217
static GstCaps *
Packit 971217
gst_video_convert_transform_caps (GstBaseTransform * btrans,
Packit 971217
    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
Packit 971217
{
Packit 971217
  GstCaps *tmp, *tmp2;
Packit 971217
  GstCaps *result;
Packit 971217
Packit 971217
  /* Get all possible caps that we can transform to */
Packit 971217
  tmp = gst_video_convert_caps_remove_format_info (caps);
Packit 971217
Packit 971217
  if (filter) {
Packit 971217
    tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
Packit 971217
    gst_caps_unref (tmp);
Packit 971217
    tmp = tmp2;
Packit 971217
  }
Packit 971217
Packit 971217
  result = tmp;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
Packit 971217
      GST_PTR_FORMAT, caps, result);
Packit 971217
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_video_convert_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
Packit 971217
    GstMeta * meta, GstBuffer * inbuf)
Packit 971217
{
Packit 971217
  const GstMetaInfo *info = meta->info;
Packit 971217
  gboolean ret;
Packit 971217
Packit 971217
  if (gst_meta_api_type_has_tag (info->api, _colorspace_quark)) {
Packit 971217
    /* don't copy colorspace specific metadata, FIXME, we need a MetaTransform
Packit 971217
     * for the colorspace metadata. */
Packit 971217
    ret = FALSE;
Packit 971217
  } else {
Packit 971217
    /* copy other metadata */
Packit 971217
    ret = TRUE;
Packit 971217
  }
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_video_convert_set_info (GstVideoFilter * filter,
Packit 971217
    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
Packit 971217
    GstVideoInfo * out_info)
Packit 971217
{
Packit 971217
  GstVideoConvert *space;
Packit 971217
Packit 971217
  space = GST_VIDEO_CONVERT_CAST (filter);
Packit 971217
Packit 971217
  if (space->convert) {
Packit 971217
    gst_video_converter_free (space->convert);
Packit 971217
    space->convert = NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  /* these must match */
Packit 971217
  if (in_info->width != out_info->width || in_info->height != out_info->height
Packit 971217
      || in_info->fps_n != out_info->fps_n || in_info->fps_d != out_info->fps_d)
Packit 971217
    goto format_mismatch;
Packit 971217
Packit 971217
  /* if present, these must match too */
Packit 971217
  if (in_info->par_n != out_info->par_n || in_info->par_d != out_info->par_d)
Packit 971217
    goto format_mismatch;
Packit 971217
Packit 971217
  /* if present, these must match too */
Packit 971217
  if (in_info->interlace_mode != out_info->interlace_mode)
Packit 971217
    goto format_mismatch;
Packit 971217
Packit 971217
Packit 971217
  space->convert = gst_video_converter_new (in_info, out_info,
Packit 971217
      gst_structure_new ("GstVideoConvertConfig",
Packit 971217
          GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD,
Packit 971217
          space->dither,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, G_TYPE_UINT,
Packit 971217
          space->dither_quantization,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD,
Packit 971217
          GST_TYPE_VIDEO_RESAMPLER_METHOD, space->chroma_resampler,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_ALPHA_MODE,
Packit 971217
          GST_TYPE_VIDEO_ALPHA_MODE, space->alpha_mode,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE,
Packit 971217
          G_TYPE_DOUBLE, space->alpha_value,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_CHROMA_MODE,
Packit 971217
          GST_TYPE_VIDEO_CHROMA_MODE, space->chroma_mode,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_MATRIX_MODE,
Packit 971217
          GST_TYPE_VIDEO_MATRIX_MODE, space->matrix_mode,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_GAMMA_MODE,
Packit 971217
          GST_TYPE_VIDEO_GAMMA_MODE, space->gamma_mode,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE,
Packit 971217
          GST_TYPE_VIDEO_PRIMARIES_MODE, space->primaries_mode,
Packit 971217
          GST_VIDEO_CONVERTER_OPT_THREADS, G_TYPE_UINT,
Packit 971217
          space->n_threads, NULL));
Packit 971217
  if (space->convert == NULL)
Packit 971217
    goto no_convert;
Packit 971217
Packit 971217
  GST_DEBUG ("reconfigured %d %d", GST_VIDEO_INFO_FORMAT (in_info),
Packit 971217
      GST_VIDEO_INFO_FORMAT (out_info));
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
format_mismatch:
Packit 971217
  {
Packit 971217
    GST_ERROR_OBJECT (space, "input and output formats do not match");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
no_convert:
Packit 971217
  {
Packit 971217
    GST_ERROR_OBJECT (space, "could not create converter");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_video_convert_finalize (GObject * obj)
Packit 971217
{
Packit 971217
  GstVideoConvert *space = GST_VIDEO_CONVERT (obj);
Packit 971217
Packit 971217
  if (space->convert) {
Packit 971217
    gst_video_converter_free (space->convert);
Packit 971217
  }
Packit 971217
Packit 971217
  G_OBJECT_CLASS (parent_class)->finalize (obj);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_video_convert_class_init (GstVideoConvertClass * klass)
Packit 971217
{
Packit 971217
  GObjectClass *gobject_class = (GObjectClass *) klass;
Packit 971217
  GstElementClass *gstelement_class = (GstElementClass *) klass;
Packit 971217
  GstBaseTransformClass *gstbasetransform_class =
Packit 971217
      (GstBaseTransformClass *) klass;
Packit 971217
  GstVideoFilterClass *gstvideofilter_class = (GstVideoFilterClass *) klass;
Packit 971217
Packit 971217
  gobject_class->set_property = gst_video_convert_set_property;
Packit 971217
  gobject_class->get_property = gst_video_convert_get_property;
Packit 971217
  gobject_class->finalize = gst_video_convert_finalize;
Packit 971217
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_class,
Packit 971217
      &gst_video_convert_src_template);
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_class,
Packit 971217
      &gst_video_convert_sink_template);
Packit 971217
Packit 971217
  gst_element_class_set_static_metadata (gstelement_class,
Packit 971217
      "Colorspace converter", "Filter/Converter/Video",
Packit 971217
      "Converts video from one colorspace to another",
Packit 971217
      "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
Packit 971217
Packit 971217
  gstbasetransform_class->transform_caps =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_video_convert_transform_caps);
Packit 971217
  gstbasetransform_class->fixate_caps =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_video_convert_fixate_caps);
Packit 971217
  gstbasetransform_class->filter_meta =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_video_convert_filter_meta);
Packit 971217
  gstbasetransform_class->transform_meta =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_video_convert_transform_meta);
Packit 971217
Packit 971217
  gstbasetransform_class->passthrough_on_same_caps = TRUE;
Packit 971217
Packit 971217
  gstvideofilter_class->set_info =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_video_convert_set_info);
Packit 971217
  gstvideofilter_class->transform_frame =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_video_convert_transform_frame);
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_class, PROP_DITHER,
Packit 971217
      g_param_spec_enum ("dither", "Dither", "Apply dithering while converting",
Packit 971217
          gst_video_dither_method_get_type (), DEFAULT_PROP_DITHER,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_DITHER_QUANTIZATION,
Packit 971217
      g_param_spec_uint ("dither-quantization", "Dither Quantize",
Packit 971217
          "Quantizer to use", 0, G_MAXUINT, DEFAULT_PROP_DITHER_QUANTIZATION,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_CHROMA_RESAMPLER,
Packit 971217
      g_param_spec_enum ("chroma-resampler", "Chroma resampler",
Packit 971217
          "Chroma resampler method", gst_video_resampler_method_get_type (),
Packit 971217
          DEFAULT_PROP_CHROMA_RESAMPLER,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_ALPHA_MODE,
Packit 971217
      g_param_spec_enum ("alpha-mode", "Alpha Mode",
Packit 971217
          "Alpha Mode to use", gst_video_alpha_mode_get_type (),
Packit 971217
          DEFAULT_PROP_ALPHA_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_ALPHA_VALUE,
Packit 971217
      g_param_spec_double ("alpha-value", "Alpha Value",
Packit 971217
          "Alpha Value to use", 0.0, 1.0,
Packit 971217
          DEFAULT_PROP_ALPHA_VALUE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_CHROMA_MODE,
Packit 971217
      g_param_spec_enum ("chroma-mode", "Chroma Mode", "Chroma Resampling Mode",
Packit 971217
          gst_video_chroma_mode_get_type (), DEFAULT_PROP_CHROMA_MODE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_MATRIX_MODE,
Packit 971217
      g_param_spec_enum ("matrix-mode", "Matrix Mode", "Matrix Conversion Mode",
Packit 971217
          gst_video_matrix_mode_get_type (), DEFAULT_PROP_MATRIX_MODE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_GAMMA_MODE,
Packit 971217
      g_param_spec_enum ("gamma-mode", "Gamma Mode", "Gamma Conversion Mode",
Packit 971217
          gst_video_gamma_mode_get_type (), DEFAULT_PROP_GAMMA_MODE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_PRIMARIES_MODE,
Packit 971217
      g_param_spec_enum ("primaries-mode", "Primaries Mode",
Packit 971217
          "Primaries Conversion Mode", gst_video_primaries_mode_get_type (),
Packit 971217
          DEFAULT_PROP_PRIMARIES_MODE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_N_THREADS,
Packit 971217
      g_param_spec_uint ("n-threads", "Threads",
Packit 971217
          "Maximum number of threads to use", 0, G_MAXUINT,
Packit 971217
          DEFAULT_PROP_N_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_video_convert_init (GstVideoConvert * space)
Packit 971217
{
Packit 971217
  space->dither = DEFAULT_PROP_DITHER;
Packit 971217
  space->dither_quantization = DEFAULT_PROP_DITHER_QUANTIZATION;
Packit 971217
  space->chroma_resampler = DEFAULT_PROP_CHROMA_RESAMPLER;
Packit 971217
  space->alpha_mode = DEFAULT_PROP_ALPHA_MODE;
Packit 971217
  space->alpha_value = DEFAULT_PROP_ALPHA_VALUE;
Packit 971217
  space->chroma_mode = DEFAULT_PROP_CHROMA_MODE;
Packit 971217
  space->matrix_mode = DEFAULT_PROP_MATRIX_MODE;
Packit 971217
  space->gamma_mode = DEFAULT_PROP_GAMMA_MODE;
Packit 971217
  space->primaries_mode = DEFAULT_PROP_PRIMARIES_MODE;
Packit 971217
  space->n_threads = DEFAULT_PROP_N_THREADS;
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_video_convert_set_property (GObject * object, guint property_id,
Packit 971217
    const GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstVideoConvert *csp;
Packit 971217
Packit 971217
  csp = GST_VIDEO_CONVERT (object);
Packit 971217
Packit 971217
  switch (property_id) {
Packit 971217
    case PROP_DITHER:
Packit 971217
      csp->dither = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_CHROMA_RESAMPLER:
Packit 971217
      csp->chroma_resampler = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_ALPHA_MODE:
Packit 971217
      csp->alpha_mode = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_ALPHA_VALUE:
Packit 971217
      csp->alpha_value = g_value_get_double (value);
Packit 971217
      break;
Packit 971217
    case PROP_CHROMA_MODE:
Packit 971217
      csp->chroma_mode = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_MATRIX_MODE:
Packit 971217
      csp->matrix_mode = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_GAMMA_MODE:
Packit 971217
      csp->gamma_mode = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_PRIMARIES_MODE:
Packit 971217
      csp->primaries_mode = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_DITHER_QUANTIZATION:
Packit 971217
      csp->dither_quantization = g_value_get_uint (value);
Packit 971217
      break;
Packit 971217
    case PROP_N_THREADS:
Packit 971217
      csp->n_threads = g_value_get_uint (value);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_video_convert_get_property (GObject * object, guint property_id,
Packit 971217
    GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstVideoConvert *csp;
Packit 971217
Packit 971217
  csp = GST_VIDEO_CONVERT (object);
Packit 971217
Packit 971217
  switch (property_id) {
Packit 971217
    case PROP_DITHER:
Packit 971217
      g_value_set_enum (value, csp->dither);
Packit 971217
      break;
Packit 971217
    case PROP_CHROMA_RESAMPLER:
Packit 971217
      g_value_set_enum (value, csp->chroma_resampler);
Packit 971217
      break;
Packit 971217
    case PROP_ALPHA_MODE:
Packit 971217
      g_value_set_enum (value, csp->alpha_mode);
Packit 971217
      break;
Packit 971217
    case PROP_ALPHA_VALUE:
Packit 971217
      g_value_set_double (value, csp->alpha_value);
Packit 971217
      break;
Packit 971217
    case PROP_CHROMA_MODE:
Packit 971217
      g_value_set_enum (value, csp->chroma_mode);
Packit 971217
      break;
Packit 971217
    case PROP_MATRIX_MODE:
Packit 971217
      g_value_set_enum (value, csp->matrix_mode);
Packit 971217
      break;
Packit 971217
    case PROP_GAMMA_MODE:
Packit 971217
      g_value_set_enum (value, csp->gamma_mode);
Packit 971217
      break;
Packit 971217
    case PROP_PRIMARIES_MODE:
Packit 971217
      g_value_set_enum (value, csp->primaries_mode);
Packit 971217
      break;
Packit 971217
    case PROP_DITHER_QUANTIZATION:
Packit 971217
      g_value_set_uint (value, csp->dither_quantization);
Packit 971217
      break;
Packit 971217
    case PROP_N_THREADS:
Packit 971217
      g_value_set_uint (value, csp->n_threads);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static GstFlowReturn
Packit 971217
gst_video_convert_transform_frame (GstVideoFilter * filter,
Packit 971217
    GstVideoFrame * in_frame, GstVideoFrame * out_frame)
Packit 971217
{
Packit 971217
  GstVideoConvert *space;
Packit 971217
Packit 971217
  space = GST_VIDEO_CONVERT_CAST (filter);
Packit 971217
Packit 971217
  GST_CAT_DEBUG_OBJECT (CAT_PERFORMANCE, filter,
Packit 971217
      "doing colorspace conversion from %s -> to %s",
Packit 971217
      GST_VIDEO_INFO_NAME (&filter->in_info),
Packit 971217
      GST_VIDEO_INFO_NAME (&filter->out_info));
Packit 971217
Packit 971217
  gst_video_converter_frame (space->convert, in_frame, out_frame);
Packit 971217
Packit 971217
  return GST_FLOW_OK;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
plugin_init (GstPlugin * plugin)
Packit 971217
{
Packit 971217
  GST_DEBUG_CATEGORY_INIT (videoconvert_debug, "videoconvert", 0,
Packit 971217
      "Colorspace Converter");
Packit 971217
Packit 971217
  GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
Packit 971217
Packit 971217
  _colorspace_quark = g_quark_from_static_string ("colorspace");
Packit 971217
Packit 971217
  return gst_element_register (plugin, "videoconvert",
Packit 971217
      GST_RANK_NONE, GST_TYPE_VIDEO_CONVERT);
Packit 971217
}
Packit 971217
Packit 971217
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
Packit 971217
    GST_VERSION_MINOR,
Packit 971217
    videoconvert, "Colorspace conversion", plugin_init, VERSION, GST_LICENSE,
Packit 971217
    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)