mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
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:
parent
10b44cc81b
commit
b339812c07
7 changed files with 1113 additions and 0 deletions
|
@ -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
22
gst/yadif/Makefile.am
Normal 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
493
gst/yadif/gstyadif.c
Normal 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
64
gst/yadif/gstyadif.h
Normal 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
161
gst/yadif/vf_yadif.c
Normal 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
109
gst/yadif/yadif.c
Normal 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
262
gst/yadif/yadif_template.c
Normal 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
|
Loading…
Reference in a new issue