yadif: Add YADIF deinterlacing filter

Code copied from Libav, commit 26e4f0c70.  Will eventually be
moved to -ugly because underlying code is GPL.
This commit is contained in:
David Schleef 2013-02-07 15:09:51 -08:00
parent 10b44cc81b
commit b339812c07
7 changed files with 1113 additions and 0 deletions

View file

@ -396,6 +396,7 @@ AG_GST_CHECK_PLUGIN(videoparsers)
AG_GST_CHECK_PLUGIN(videosignal)
AG_GST_CHECK_PLUGIN(vmnc)
AG_GST_CHECK_PLUGIN(y4m)
AG_GST_CHECK_PLUGIN(yadif)
dnl *** plug-ins to exclude ***
@ -2248,6 +2249,7 @@ gst/videoparsers/Makefile
gst/videosignal/Makefile
gst/vmnc/Makefile
gst/y4m/Makefile
gst/yadif/Makefile
gst-libs/Makefile
gst-libs/gst/Makefile
gst-libs/gst/basecamerabinsrc/Makefile

22
gst/yadif/Makefile.am Normal file
View file

@ -0,0 +1,22 @@
plugin_LTLIBRARIES = libgstyadif.la
libgstyadif_la_SOURCES = gstyadif.c gstyadif.h vf_yadif.c yadif.c
libgstyadif_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstyadif_la_LIBADD = -lgstvideo-1.0 $(GST_BASE_LIBS) $(GST_LIBS)
libgstyadif_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstyadif_la_LIBTOOLFLAGS = --tag=disable-static
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
-:PROJECT libgstyadif -:SHARED libgstyadif \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-:SOURCES $(libgstyadif_la_SOURCES) \
-:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstyadif_la_CFLAGS) \
-:LDFLAGS $(libgstyadif_la_LDFLAGS) \
$(libgstyadif_la_LIBADD) \
-ldl \
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
> $@

493
gst/yadif/gstyadif.c Normal file
View file

@ -0,0 +1,493 @@
/* GStreamer
* Copyright (C) 2013 David Schleef <ds@schleef.org>
* Copyright (C) 2013 Rdio, Inc. <ingestions@rd.io>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
* Boston, MA 02110-1335, USA.
*/
/**
* SECTION:element-gstyadif
*
* The yadif element deinterlaces video, using the YADIF deinterlacing
* filter copied from Libav. This element only handles the simple case
* of interlaced-mode=interleaved video instead of the more complex
* inverse telecine and deinterlace cases that are handled by the
* deinterlace element.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch -v videotestsrc pattern=ball ! interlace ! yadif ! xvimagesink
* ]|
* This pipeline creates an interlaced test pattern, and then deinterlaces
* it using the yadif filter.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
#include "gstyadif.h"
GST_DEBUG_CATEGORY_STATIC (gst_yadif_debug_category);
#define GST_CAT_DEFAULT gst_yadif_debug_category
/* prototypes */
static void gst_yadif_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec);
static void gst_yadif_get_property (GObject * object,
guint property_id, GValue * value, GParamSpec * pspec);
static void gst_yadif_dispose (GObject * object);
static void gst_yadif_finalize (GObject * object);
static GstCaps *gst_yadif_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static GstCaps *gst_yadif_fixate_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
static gboolean gst_yadif_accept_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps);
static gboolean gst_yadif_set_caps (GstBaseTransform * trans, GstCaps * incaps,
GstCaps * outcaps);
static gboolean gst_yadif_query (GstBaseTransform * trans,
GstPadDirection direction, GstQuery * query);
static gboolean gst_yadif_decide_allocation (GstBaseTransform * trans,
GstQuery * query);
static gboolean gst_yadif_filter_meta (GstBaseTransform * trans,
GstQuery * query, GType api, const GstStructure * params);
static gboolean gst_yadif_propose_allocation (GstBaseTransform * trans,
GstQuery * decide_query, GstQuery * query);
static gboolean gst_yadif_transform_size (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps,
gsize * othersize);
static gboolean gst_yadif_get_unit_size (GstBaseTransform * trans,
GstCaps * caps, gsize * size);
static gboolean gst_yadif_start (GstBaseTransform * trans);
static gboolean gst_yadif_stop (GstBaseTransform * trans);
static gboolean gst_yadif_sink_event (GstBaseTransform * trans,
GstEvent * event);
static gboolean gst_yadif_src_event (GstBaseTransform * trans,
GstEvent * event);
static GstFlowReturn gst_yadif_prepare_output_buffer (GstBaseTransform * trans,
GstBuffer * input, GstBuffer ** outbuf);
static gboolean gst_yadif_copy_metadata (GstBaseTransform * trans,
GstBuffer * input, GstBuffer * outbuf);
static gboolean gst_yadif_transform_meta (GstBaseTransform * trans,
GstBuffer * outbuf, GstMeta * meta, GstBuffer * inbuf);
static void gst_yadif_before_transform (GstBaseTransform * trans,
GstBuffer * buffer);
static GstFlowReturn gst_yadif_transform (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer * outbuf);
static GstFlowReturn gst_yadif_transform_ip (GstBaseTransform * trans,
GstBuffer * buf);
enum
{
PROP_0
};
/* pad templates */
static GstStaticPadTemplate gst_yadif_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{Y42B,I420,Y444}")
",interlace-mode=(string){interleaved,mixed,progressive}")
);
static GstStaticPadTemplate gst_yadif_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{Y42B,I420,Y444}")
",interlace-mode=(string)progressive")
);
/* class initialization */
G_DEFINE_TYPE_WITH_CODE (GstYadif, gst_yadif, GST_TYPE_BASE_TRANSFORM,
GST_DEBUG_CATEGORY_INIT (gst_yadif_debug_category, "yadif", 0,
"debug category for yadif element"));
static void
gst_yadif_class_init (GstYadifClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstBaseTransformClass *base_transform_class =
GST_BASE_TRANSFORM_CLASS (klass);
/* Setting up pads and setting metadata should be moved to
base_class_init if you intend to subclass this class. */
gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
gst_static_pad_template_get (&gst_yadif_sink_template));
gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
gst_static_pad_template_get (&gst_yadif_src_template));
gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
"YADIF deinterlacer", "Video/Filter",
"Deinterlace video using YADIF filter", "David Schleef <ds@schleef.org>");
gobject_class->set_property = gst_yadif_set_property;
gobject_class->get_property = gst_yadif_get_property;
gobject_class->dispose = gst_yadif_dispose;
gobject_class->finalize = gst_yadif_finalize;
base_transform_class->transform_caps =
GST_DEBUG_FUNCPTR (gst_yadif_transform_caps);
if (0)
base_transform_class->fixate_caps =
GST_DEBUG_FUNCPTR (gst_yadif_fixate_caps);
if (0)
base_transform_class->accept_caps =
GST_DEBUG_FUNCPTR (gst_yadif_accept_caps);
base_transform_class->set_caps = GST_DEBUG_FUNCPTR (gst_yadif_set_caps);
if (0)
base_transform_class->query = GST_DEBUG_FUNCPTR (gst_yadif_query);
if (0)
base_transform_class->decide_allocation =
GST_DEBUG_FUNCPTR (gst_yadif_decide_allocation);
if (0)
base_transform_class->filter_meta =
GST_DEBUG_FUNCPTR (gst_yadif_filter_meta);
if (0)
base_transform_class->propose_allocation =
GST_DEBUG_FUNCPTR (gst_yadif_propose_allocation);
if (0)
base_transform_class->transform_size =
GST_DEBUG_FUNCPTR (gst_yadif_transform_size);
base_transform_class->get_unit_size =
GST_DEBUG_FUNCPTR (gst_yadif_get_unit_size);
base_transform_class->start = GST_DEBUG_FUNCPTR (gst_yadif_start);
base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_yadif_stop);
if (0)
base_transform_class->sink_event = GST_DEBUG_FUNCPTR (gst_yadif_sink_event);
if (0)
base_transform_class->src_event = GST_DEBUG_FUNCPTR (gst_yadif_src_event);
if (0)
base_transform_class->prepare_output_buffer =
GST_DEBUG_FUNCPTR (gst_yadif_prepare_output_buffer);
if (0)
base_transform_class->copy_metadata =
GST_DEBUG_FUNCPTR (gst_yadif_copy_metadata);
if (0)
base_transform_class->transform_meta =
GST_DEBUG_FUNCPTR (gst_yadif_transform_meta);
if (0)
base_transform_class->before_transform =
GST_DEBUG_FUNCPTR (gst_yadif_before_transform);
base_transform_class->transform = GST_DEBUG_FUNCPTR (gst_yadif_transform);
if (0)
base_transform_class->transform_ip =
GST_DEBUG_FUNCPTR (gst_yadif_transform_ip);
}
static void
gst_yadif_init (GstYadif * yadif)
{
yadif->sinkpad = gst_pad_new_from_static_template (&gst_yadif_sink_template,
"sink");
yadif->srcpad = gst_pad_new_from_static_template (&gst_yadif_src_template,
"src");
}
void
gst_yadif_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
/* GstYadif *yadif = GST_YADIF (object); */
switch (property_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
void
gst_yadif_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
/* GstYadif *yadif = GST_YADIF (object); */
switch (property_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
void
gst_yadif_dispose (GObject * object)
{
/* GstYadif *yadif = GST_YADIF (object); */
/* clean up as possible. may be called multiple times */
G_OBJECT_CLASS (gst_yadif_parent_class)->dispose (object);
}
void
gst_yadif_finalize (GObject * object)
{
/* GstYadif *yadif = GST_YADIF (object); */
/* clean up object here */
G_OBJECT_CLASS (gst_yadif_parent_class)->finalize (object);
}
static GstCaps *
gst_yadif_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstCaps *othercaps;
othercaps = gst_caps_copy (caps);
if (direction == GST_PAD_SRC) {
GValue value = G_VALUE_INIT;
GValue v = G_VALUE_INIT;
g_value_init (&value, GST_TYPE_LIST);
g_value_init (&v, G_TYPE_STRING);
g_value_set_string (&v, "interleaved");
gst_value_list_append_value (&value, &v);
g_value_set_string (&v, "mixed");
gst_value_list_append_value (&value, &v);
g_value_set_string (&v, "progressive");
gst_value_list_append_value (&value, &v);
gst_caps_set_value (othercaps, "interlace-mode", &value);
g_value_reset (&value);
g_value_reset (&v);
} else {
gst_caps_set_simple (othercaps, "interlace-mode", G_TYPE_STRING,
"progressive", NULL);
}
return othercaps;
}
static GstCaps *
gst_yadif_fixate_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
{
return NULL;
}
static gboolean
gst_yadif_accept_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps)
{
return TRUE;
}
static gboolean
gst_yadif_set_caps (GstBaseTransform * trans, GstCaps * incaps,
GstCaps * outcaps)
{
GstYadif *yadif = GST_YADIF (trans);
gst_video_info_from_caps (&yadif->video_info, incaps);
return TRUE;
}
static gboolean
gst_yadif_query (GstBaseTransform * trans, GstPadDirection direction,
GstQuery * query)
{
return TRUE;
}
static gboolean
gst_yadif_decide_allocation (GstBaseTransform * trans, GstQuery * query)
{
return TRUE;
}
static gboolean
gst_yadif_filter_meta (GstBaseTransform * trans, GstQuery * query,
GType api, const GstStructure * params)
{
return TRUE;
}
static gboolean
gst_yadif_propose_allocation (GstBaseTransform * trans,
GstQuery * decide_query, GstQuery * query)
{
return TRUE;
}
static gboolean
gst_yadif_transform_size (GstBaseTransform * trans,
GstPadDirection direction,
GstCaps * caps, gsize size, GstCaps * othercaps, gsize * othersize)
{
return FALSE;
}
static gboolean
gst_yadif_get_unit_size (GstBaseTransform * trans, GstCaps * caps, gsize * size)
{
GstVideoInfo info;
if (gst_video_info_from_caps (&info, caps)) {
*size = GST_VIDEO_INFO_SIZE (&info);
return TRUE;
}
return FALSE;
}
static gboolean
gst_yadif_start (GstBaseTransform * trans)
{
return TRUE;
}
static gboolean
gst_yadif_stop (GstBaseTransform * trans)
{
return TRUE;
}
static gboolean
gst_yadif_sink_event (GstBaseTransform * trans, GstEvent * event)
{
return TRUE;
}
static gboolean
gst_yadif_src_event (GstBaseTransform * trans, GstEvent * event)
{
return TRUE;
}
static GstFlowReturn
gst_yadif_prepare_output_buffer (GstBaseTransform * trans,
GstBuffer * input, GstBuffer ** buf)
{
return GST_FLOW_ERROR;
}
static gboolean
gst_yadif_copy_metadata (GstBaseTransform * trans,
GstBuffer * input, GstBuffer * outbuf)
{
return TRUE;
}
static gboolean
gst_yadif_transform_meta (GstBaseTransform * trans,
GstBuffer * outbuf, GstMeta * meta, GstBuffer * inbuf)
{
return TRUE;
}
static void
gst_yadif_before_transform (GstBaseTransform * trans, GstBuffer * buffer)
{
}
void yadif_filter (GstYadif * yadif, int parity, int tff);
static GstFlowReturn
gst_yadif_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstYadif *yadif = GST_YADIF (trans);
int parity;
int tff;
parity = 0;
tff = 0;
if (!gst_video_frame_map (&yadif->dest_frame, &yadif->video_info, outbuf,
GST_MAP_WRITE))
goto dest_map_failed;
if (!gst_video_frame_map (&yadif->cur_frame, &yadif->video_info, inbuf,
GST_MAP_READ))
goto src_map_failed;
yadif->next_frame = yadif->cur_frame;
yadif->prev_frame = yadif->cur_frame;
yadif_filter (yadif, parity, tff);
gst_video_frame_unmap (&yadif->dest_frame);
gst_video_frame_unmap (&yadif->cur_frame);
return GST_FLOW_OK;
dest_map_failed:
{
GST_ERROR_OBJECT (yadif, "failed to map dest");
return GST_FLOW_ERROR;
}
src_map_failed:
{
GST_ERROR_OBJECT (yadif, "failed to map src");
gst_video_frame_unmap (&yadif->dest_frame);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_yadif_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{
return GST_FLOW_OK;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "yadif", GST_RANK_NONE, GST_TYPE_YADIF);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
yadif,
"YADIF deinterlacing filter",
plugin_init, VERSION, "GPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)

64
gst/yadif/gstyadif.h Normal file
View file

@ -0,0 +1,64 @@
/* GStreamer
* Copyright (C) 2013 Rdio, Inc. <ingestions@rd.io>
* Copyright (C) 2013 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.
*/
#ifndef _GST_YADIF_H_
#define _GST_YADIF_H_
#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
G_BEGIN_DECLS
#define GST_TYPE_YADIF (gst_yadif_get_type())
#define GST_YADIF(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_YADIF,GstYadif))
#define GST_YADIF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_YADIF,GstYadifClass))
#define GST_IS_YADIF(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_YADIF))
#define GST_IS_YADIF_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_YADIF))
typedef struct _GstYadif GstYadif;
typedef struct _GstYadifClass GstYadifClass;
struct _GstYadif
{
GstBaseTransform base_yadif;
GstPad *sinkpad;
GstPad *srcpad;
int mode;
GstVideoInfo video_info;
GstVideoFrame prev_frame;
GstVideoFrame cur_frame;
GstVideoFrame next_frame;
GstVideoFrame dest_frame;
};
struct _GstYadifClass
{
GstBaseTransformClass base_yadif_class;
};
GType gst_yadif_get_type (void);
G_END_DECLS
#endif

161
gst/yadif/vf_yadif.c Normal file
View file

@ -0,0 +1,161 @@
/*
* Copyright (C) 2013 David Schleef <ds@schleef.org>
* Copyright (C) 2013 Rdio, Inc. <ingestions@rd.io>
* Copyright (C) 2006-2010 Michael Niedermayer <michaelni@gmx.at>
* 2010 James Darnley <james.darnley@gmail.com>
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Libav 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with Libav; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <gstyadif.h>
#include <string.h>
#undef NDEBUG
#include <assert.h>
#define FFABS(a) ABS(a)
#define FFMIN(a,b) MIN(a,b)
#define FFMAX(a,b) MAX(a,b)
#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)
#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)
#define PERM_RWP AV_PERM_WRITE | AV_PERM_PRESERVE | AV_PERM_REUSE
#define CHECK(j)\
{ int score = FFABS(cur[mrefs-1+(j)] - cur[prefs-1-(j)])\
+ FFABS(cur[mrefs +(j)] - cur[prefs -(j)])\
+ FFABS(cur[mrefs+1+(j)] - cur[prefs+1-(j)]);\
if (score < spatial_score) {\
spatial_score= score;\
spatial_pred= (cur[mrefs +(j)] + cur[prefs -(j)])>>1;\
#define FILTER \
for (x = 0; x < w; x++) { \
int c = cur[mrefs]; \
int d = (prev2[0] + next2[0])>>1; \
int e = cur[prefs]; \
int temporal_diff0 = FFABS(prev2[0] - next2[0]); \
int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1; \
int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1; \
int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \
int spatial_pred = (c+e) >> 1; \
int spatial_score = FFABS(cur[mrefs - 1] - cur[prefs - 1]) + FFABS(c-e) \
+ FFABS(cur[mrefs + 1] - cur[prefs + 1]) - 1; \
\
CHECK(-1) CHECK(-2) }} }} \
CHECK( 1) CHECK( 2) }} }} \
\
if (mode < 2) { \
int b = (prev2[2 * mrefs] + next2[2 * mrefs])>>1; \
int f = (prev2[2 * prefs] + next2[2 * prefs])>>1; \
int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \
int min = FFMIN3(d - e, d - c, FFMAX(b - c, f - e)); \
\
diff = FFMAX3(diff, min, -max); \
} \
\
if (spatial_pred > d + diff) \
spatial_pred = d + diff; \
else if (spatial_pred < d - diff) \
spatial_pred = d - diff; \
\
dst[0] = spatial_pred; \
\
dst++; \
cur++; \
prev++; \
next++; \
prev2++; \
next2++; \
}
static void
filter_line_c (guint8 * dst,
guint8 * prev, guint8 * cur, guint8 * next,
int w, int prefs, int mrefs, int parity, int mode)
{
int x;
guint8 *prev2 = parity ? prev : cur;
guint8 *next2 = parity ? cur : next;
FILTER}
#if 0
static void
filter_line_c_16bit (guint16 * dst,
guint16 * prev, guint16 * cur, guint16 * next,
int w, int prefs, int mrefs, int parity, int mode)
{
int x;
guint16 *prev2 = parity ? prev : cur;
guint16 *next2 = parity ? cur : next;
mrefs /= 2;
prefs /= 2;
FILTER}
#endif
void yadif_filter (GstYadif * yadif, int parity, int tff);
void filter_line_x86 (guint8 * dst,
guint8 * prev, guint8 * cur, guint8 * next,
int w, int prefs, int mrefs, int parity, int mode);
void
yadif_filter (GstYadif * yadif, int parity, int tff)
{
int y, i;
const GstVideoInfo *vi = &yadif->video_info;
const GstVideoFormatInfo *vfi = vi->finfo;
for (i = 0; i < GST_VIDEO_FORMAT_INFO_N_COMPONENTS (vfi); i++) {
int w = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vfi, i, vi->width);
int h = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vfi, i, vi->height);
int refs = GST_VIDEO_INFO_COMP_STRIDE (vi, i);
int df = GST_VIDEO_INFO_COMP_PSTRIDE (vi, i);
guint8 *prev_data = GST_VIDEO_FRAME_COMP_DATA (&yadif->prev_frame, i);
guint8 *cur_data = GST_VIDEO_FRAME_COMP_DATA (&yadif->cur_frame, i);
guint8 *next_data = GST_VIDEO_FRAME_COMP_DATA (&yadif->next_frame, i);
guint8 *dest_data = GST_VIDEO_FRAME_COMP_DATA (&yadif->dest_frame, i);
for (y = 0; y < h; y++) {
if ((y ^ parity) & 1) {
guint8 *prev = prev_data + y * refs;
guint8 *cur = cur_data + y * refs;
guint8 *next = next_data + y * refs;
guint8 *dst = dest_data + y * refs;
int mode = ((y == 1) || (y + 2 == h)) ? 2 : yadif->mode;
if (0) {
filter_line_c (dst, prev, cur, next, w,
y + 1 < h ? refs : -refs, y ? -refs : refs, parity ^ tff, mode);
} else {
filter_line_x86 (dst, prev, cur, next, w,
y + 1 < h ? refs : -refs, y ? -refs : refs, parity ^ tff, mode);
}
} else {
guint8 *dst = dest_data + y * refs;
guint8 *cur = cur_data + y * refs;
memcpy (dst, cur, w * df);
}
}
}
#if 0
emms_c ();
#endif
}

109
gst/yadif/yadif.c Normal file
View file

@ -0,0 +1,109 @@
/*
* Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Libav 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with Libav; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <glib.h>
#if 0
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
#include "libavutil/x86/asm.h"
#include "libavcodec/x86/dsputil_mmx.h"
#include "libavfilter/yadif.h"
#endif
//#if HAVE_INLINE_ASM
typedef struct xmm_reg
{
guint64 a, b;
} xmm_reg;
typedef gint64 x86_reg;
#define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v
#define DECLARE_ASM_CONST(n,t,v) static const t __attribute__((used)) __attribute__ ((aligned (n))) v
#define ARCH_X86_64 1
//#if ARCH_X86_64 && defined(__PIC__)
#if 1
# define LOCAL_MANGLE(a) #a "(%%rip)"
#else
# define LOCAL_MANGLE(a) #a
#endif
#define EXTERN_PREFIX ""
#define MANGLE(a) EXTERN_PREFIX LOCAL_MANGLE(a)
DECLARE_ASM_CONST (16, const xmm_reg, pb_1) = {
0x0101010101010101ULL, 0x0101010101010101ULL};
DECLARE_ASM_CONST (16, const xmm_reg, pw_1) = {
0x0001000100010001ULL, 0x0001000100010001ULL};
#if HAVE_SSSE3_INLINE
#define COMPILE_TEMPLATE_SSE2 1
#define COMPILE_TEMPLATE_SSSE3 1
#undef RENAME
#define RENAME(a) a ## _ssse3
#include "yadif_template.c"
#undef COMPILE_TEMPLATE_SSSE3
#endif
//#if HAVE_SSE2_INLINE
#undef RENAME
#define RENAME(a) a ## _sse2
#include "yadif_template.c"
#undef COMPILE_TEMPLATE_SSE2
//#endif
#if HAVE_MMXEXT_INLINE
#undef RENAME
#define RENAME(a) a ## _mmxext
#include "yadif_template.c"
#endif
//#endif /* HAVE_INLINE_ASM */
void filter_line_x86 (guint8 * dst,
guint8 * prev, guint8 * cur, guint8 * next,
int w, int prefs, int mrefs, int parity, int mode);
void
filter_line_x86 (guint8 * dst,
guint8 * prev, guint8 * cur, guint8 * next,
int w, int prefs, int mrefs, int parity, int mode)
{
#if 0
#if HAVE_MMXEXT_INLINE
if (cpu_flags & AV_CPU_FLAG_MMXEXT)
yadif->filter_line = yadif_filter_line_mmxext;
#endif
#if HAVE_SSE2_INLINE
if (cpu_flags & AV_CPU_FLAG_SSE2)
yadif->filter_line = yadif_filter_line_sse2;
#endif
#if HAVE_SSSE3_INLINE
if (cpu_flags & AV_CPU_FLAG_SSSE3)
yadif->filter_line = yadif_filter_line_ssse3;
#endif
#endif
yadif_filter_line_sse2 (dst, prev, cur, next, w, prefs, mrefs, parity, mode);
}

262
gst/yadif/yadif_template.c Normal file
View file

@ -0,0 +1,262 @@
/*
* Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Libav 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with Libav; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef COMPILE_TEMPLATE_SSE2
#define MM "%%xmm"
#define MOV "movq"
#define MOVQ "movdqa"
#define MOVQU "movdqu"
#define STEP 8
#define LOAD(mem,dst) \
MOV" "mem", "dst" \n\t"\
"punpcklbw "MM"7, "dst" \n\t"
#define PSRL1(reg) "psrldq $1, "reg" \n\t"
#define PSRL2(reg) "psrldq $2, "reg" \n\t"
#define PSHUF(src,dst) "movdqa "dst", "src" \n\t"\
"psrldq $2, "src" \n\t"
#else
#define MM "%%mm"
#define MOV "movd"
#define MOVQ "movq"
#define MOVQU "movq"
#define STEP 4
#define LOAD(mem,dst) \
MOV" "mem", "dst" \n\t"\
"punpcklbw "MM"7, "dst" \n\t"
#define PSRL1(reg) "psrlq $8, "reg" \n\t"
#define PSRL2(reg) "psrlq $16, "reg" \n\t"
#define PSHUF(src,dst) "pshufw $9, "dst", "src" \n\t"
#endif
#ifdef COMPILE_TEMPLATE_SSSE3
#define PABS(tmp,dst) \
"pabsw "dst", "dst" \n\t"
#else
#define PABS(tmp,dst) \
"pxor "tmp", "tmp" \n\t"\
"psubw "dst", "tmp" \n\t"\
"pmaxsw "tmp", "dst" \n\t"
#endif
#define CHECK(pj,mj) \
MOVQU" "#pj"(%[cur],%[mrefs]), "MM"2 \n\t" /* cur[x-refs-1+j] */\
MOVQU" "#mj"(%[cur],%[prefs]), "MM"3 \n\t" /* cur[x+refs-1-j] */\
MOVQ" "MM"2, "MM"4 \n\t"\
MOVQ" "MM"2, "MM"5 \n\t"\
"pxor "MM"3, "MM"4 \n\t"\
"pavgb "MM"3, "MM"5 \n\t"\
"pand "MANGLE(pb_1)", "MM"4 \n\t"\
"psubusb "MM"4, "MM"5 \n\t"\
PSRL1(MM"5") \
"punpcklbw "MM"7, "MM"5 \n\t" /* (cur[x-refs+j] + cur[x+refs-j])>>1 */\
MOVQ" "MM"2, "MM"4 \n\t"\
"psubusb "MM"3, "MM"2 \n\t"\
"psubusb "MM"4, "MM"3 \n\t"\
"pmaxub "MM"3, "MM"2 \n\t"\
MOVQ" "MM"2, "MM"3 \n\t"\
MOVQ" "MM"2, "MM"4 \n\t" /* ABS(cur[x-refs-1+j] - cur[x+refs-1-j]) */\
PSRL1(MM"3") /* ABS(cur[x-refs +j] - cur[x+refs -j]) */\
PSRL2(MM"4") /* ABS(cur[x-refs+1+j] - cur[x+refs+1-j]) */\
"punpcklbw "MM"7, "MM"2 \n\t"\
"punpcklbw "MM"7, "MM"3 \n\t"\
"punpcklbw "MM"7, "MM"4 \n\t"\
"paddw "MM"3, "MM"2 \n\t"\
"paddw "MM"4, "MM"2 \n\t" /* score */
#define CHECK1 \
MOVQ" "MM"0, "MM"3 \n\t"\
"pcmpgtw "MM"2, "MM"3 \n\t" /* if(score < spatial_score) */\
"pminsw "MM"2, "MM"0 \n\t" /* spatial_score= score; */\
MOVQ" "MM"3, "MM"6 \n\t"\
"pand "MM"3, "MM"5 \n\t"\
"pandn "MM"1, "MM"3 \n\t"\
"por "MM"5, "MM"3 \n\t"\
MOVQ" "MM"3, "MM"1 \n\t" /* spatial_pred= (cur[x-refs+j] + cur[x+refs-j])>>1; */
#define CHECK2 /* pretend not to have checked dir=2 if dir=1 was bad.\
hurts both quality and speed, but matches the C version. */\
"paddw "MANGLE(pw_1)", "MM"6 \n\t"\
"psllw $14, "MM"6 \n\t"\
"paddsw "MM"6, "MM"2 \n\t"\
MOVQ" "MM"0, "MM"3 \n\t"\
"pcmpgtw "MM"2, "MM"3 \n\t"\
"pminsw "MM"2, "MM"0 \n\t"\
"pand "MM"3, "MM"5 \n\t"\
"pandn "MM"1, "MM"3 \n\t"\
"por "MM"5, "MM"3 \n\t"\
MOVQ" "MM"3, "MM"1 \n\t"
static void RENAME (yadif_filter_line) (guint8 * dst, guint8 * prev,
guint8 * cur, guint8 * next, int w, int prefs, int mrefs, int parity,
int mode)
{
DECLARE_ALIGNED (16, guint8, tmp)[16 * 4];
int x;
#define FILTER\
for(x=0; x<w; x+=STEP){\
__asm__ volatile(\
"pxor "MM"7, "MM"7 \n\t"\
LOAD("(%[cur],%[mrefs])", MM"0") /* c = cur[x-refs] */\
LOAD("(%[cur],%[prefs])", MM"1") /* e = cur[x+refs] */\
LOAD("(%["prev2"])", MM"2") /* prev2[x] */\
LOAD("(%["next2"])", MM"3") /* next2[x] */\
MOVQ" "MM"3, "MM"4 \n\t"\
"paddw "MM"2, "MM"3 \n\t"\
"psraw $1, "MM"3 \n\t" /* d = (prev2[x] + next2[x])>>1 */\
MOVQ" "MM"0, (%[tmp]) \n\t" /* c */\
MOVQ" "MM"3, 16(%[tmp]) \n\t" /* d */\
MOVQ" "MM"1, 32(%[tmp]) \n\t" /* e */\
"psubw "MM"4, "MM"2 \n\t"\
PABS( MM"4", MM"2") /* temporal_diff0 */\
LOAD("(%[prev],%[mrefs])", MM"3") /* prev[x-refs] */\
LOAD("(%[prev],%[prefs])", MM"4") /* prev[x+refs] */\
"psubw "MM"0, "MM"3 \n\t"\
"psubw "MM"1, "MM"4 \n\t"\
PABS( MM"5", MM"3")\
PABS( MM"5", MM"4")\
"paddw "MM"4, "MM"3 \n\t" /* temporal_diff1 */\
"psrlw $1, "MM"2 \n\t"\
"psrlw $1, "MM"3 \n\t"\
"pmaxsw "MM"3, "MM"2 \n\t"\
LOAD("(%[next],%[mrefs])", MM"3") /* next[x-refs] */\
LOAD("(%[next],%[prefs])", MM"4") /* next[x+refs] */\
"psubw "MM"0, "MM"3 \n\t"\
"psubw "MM"1, "MM"4 \n\t"\
PABS( MM"5", MM"3")\
PABS( MM"5", MM"4")\
"paddw "MM"4, "MM"3 \n\t" /* temporal_diff2 */\
"psrlw $1, "MM"3 \n\t"\
"pmaxsw "MM"3, "MM"2 \n\t"\
MOVQ" "MM"2, 48(%[tmp]) \n\t" /* diff */\
\
"paddw "MM"0, "MM"1 \n\t"\
"paddw "MM"0, "MM"0 \n\t"\
"psubw "MM"1, "MM"0 \n\t"\
"psrlw $1, "MM"1 \n\t" /* spatial_pred */\
PABS( MM"2", MM"0") /* ABS(c-e) */\
\
MOVQU" -1(%[cur],%[mrefs]), "MM"2 \n\t" /* cur[x-refs-1] */\
MOVQU" -1(%[cur],%[prefs]), "MM"3 \n\t" /* cur[x+refs-1] */\
MOVQ" "MM"2, "MM"4 \n\t"\
"psubusb "MM"3, "MM"2 \n\t"\
"psubusb "MM"4, "MM"3 \n\t"\
"pmaxub "MM"3, "MM"2 \n\t"\
PSHUF(MM"3", MM"2") \
"punpcklbw "MM"7, "MM"2 \n\t" /* ABS(cur[x-refs-1] - cur[x+refs-1]) */\
"punpcklbw "MM"7, "MM"3 \n\t" /* ABS(cur[x-refs+1] - cur[x+refs+1]) */\
"paddw "MM"2, "MM"0 \n\t"\
"paddw "MM"3, "MM"0 \n\t"\
"psubw "MANGLE(pw_1)", "MM"0 \n\t" /* spatial_score */\
\
CHECK(-2,0)\
CHECK1\
CHECK(-3,1)\
CHECK2\
CHECK(0,-2)\
CHECK1\
CHECK(1,-3)\
CHECK2\
\
/* if(p->mode<2) ... */\
MOVQ" 48(%[tmp]), "MM"6 \n\t" /* diff */\
"cmpl $2, %[mode] \n\t"\
"jge 1f \n\t"\
LOAD("(%["prev2"],%[mrefs],2)", MM"2") /* prev2[x-2*refs] */\
LOAD("(%["next2"],%[mrefs],2)", MM"4") /* next2[x-2*refs] */\
LOAD("(%["prev2"],%[prefs],2)", MM"3") /* prev2[x+2*refs] */\
LOAD("(%["next2"],%[prefs],2)", MM"5") /* next2[x+2*refs] */\
"paddw "MM"4, "MM"2 \n\t"\
"paddw "MM"5, "MM"3 \n\t"\
"psrlw $1, "MM"2 \n\t" /* b */\
"psrlw $1, "MM"3 \n\t" /* f */\
MOVQ" (%[tmp]), "MM"4 \n\t" /* c */\
MOVQ" 16(%[tmp]), "MM"5 \n\t" /* d */\
MOVQ" 32(%[tmp]), "MM"7 \n\t" /* e */\
"psubw "MM"4, "MM"2 \n\t" /* b-c */\
"psubw "MM"7, "MM"3 \n\t" /* f-e */\
MOVQ" "MM"5, "MM"0 \n\t"\
"psubw "MM"4, "MM"5 \n\t" /* d-c */\
"psubw "MM"7, "MM"0 \n\t" /* d-e */\
MOVQ" "MM"2, "MM"4 \n\t"\
"pminsw "MM"3, "MM"2 \n\t"\
"pmaxsw "MM"4, "MM"3 \n\t"\
"pmaxsw "MM"5, "MM"2 \n\t"\
"pminsw "MM"5, "MM"3 \n\t"\
"pmaxsw "MM"0, "MM"2 \n\t" /* max */\
"pminsw "MM"0, "MM"3 \n\t" /* min */\
"pxor "MM"4, "MM"4 \n\t"\
"pmaxsw "MM"3, "MM"6 \n\t"\
"psubw "MM"2, "MM"4 \n\t" /* -max */\
"pmaxsw "MM"4, "MM"6 \n\t" /* diff= MAX3(diff, min, -max); */\
"1: \n\t"\
\
MOVQ" 16(%[tmp]), "MM"2 \n\t" /* d */\
MOVQ" "MM"2, "MM"3 \n\t"\
"psubw "MM"6, "MM"2 \n\t" /* d-diff */\
"paddw "MM"6, "MM"3 \n\t" /* d+diff */\
"pmaxsw "MM"2, "MM"1 \n\t"\
"pminsw "MM"3, "MM"1 \n\t" /* d = clip(spatial_pred, d-diff, d+diff); */\
"packuswb "MM"1, "MM"1 \n\t"\
\
::[prev] "r"(prev),\
[cur] "r"(cur),\
[next] "r"(next),\
[prefs]"r"((x86_reg)prefs),\
[mrefs]"r"((x86_reg)mrefs),\
[mode] "g"(mode),\
[tmp] "r"(tmp)\
);\
__asm__ volatile(MOV" "MM"1, %0" :"=m"(*dst));\
dst += STEP;\
prev+= STEP;\
cur += STEP;\
next+= STEP;\
}
if (parity) {
#define prev2 "prev"
#define next2 "cur"
FILTER
#undef prev2
#undef next2
} else {
#define prev2 "cur"
#define next2 "next"
FILTER
#undef prev2
#undef next2
}
}
#undef STEP
#undef MM
#undef MOV
#undef MOVQ
#undef MOVQU
#undef PSHUF
#undef PSRL1
#undef PSRL2
#undef LOAD
#undef PABS
#undef CHECK
#undef CHECK1
#undef CHECK2
#undef FILTER