[MOVED FROM BAD 01/56] gst/deinterlace2/: Add a deinterlacer plugin based on the tvtime/DScaler deinterlacer, which was relicensed to LGPL f...

Original commit message from CVS:
Based on a patch by: Martin Eikermann <meiker at upb dot de>
* gst/deinterlace2/Makefile.am:
* gst/deinterlace2/gstdeinterlace2.c:
(gst_deinterlace2_method_get_type),
(gst_deinterlace2_fields_get_type),
(gst_deinterlace2_field_layout_get_type),
(gst_deinterlace2_base_init), (gst_deinterlace2_class_init),
(gst_deinterlace2_init), (gst_deinterlace2_set_method),
(gst_deinterlace2_set_property), (gst_deinterlace2_get_property),
(gst_deinterlace2_finalize), (gst_deinterlace2_pop_history),
(gst_deinterlace2_head_history), (gst_deinterlace2_push_history),
(gst_deinterlace2_deinterlace_scanlines), (gst_deinterlace2_chain),
(gst_deinterlace2_setcaps), (gst_deinterlace2_sink_event),
(gst_deinterlace2_change_state), (gst_deinterlace2_src_event),
(gst_deinterlace2_src_query), (gst_deinterlace2_src_query_types),
(plugin_init):
* gst/deinterlace2/gstdeinterlace2.h:
* gst/deinterlace2/tvtime/greedy.c: (copy_scanline),
(deinterlace_greedy_packed422_scanline_mmxext),
(dscaler_greedyl_get_method):
* gst/deinterlace2/tvtime/greedyh.asm:
* gst/deinterlace2/tvtime/greedyh.c:
(deinterlace_frame_di_greedyh), (dscaler_greedyh_get_method),
(greedyh_init), (greedyh_filter_mmx), (greedyh_filter_3dnow),
(greedyh_filter_sse):
* gst/deinterlace2/tvtime/greedyh.h:
* gst/deinterlace2/tvtime/greedyhmacros.h:
* gst/deinterlace2/tvtime/mmx.h:
* gst/deinterlace2/tvtime/plugins.h:
* gst/deinterlace2/tvtime/speedtools.h:
* gst/deinterlace2/tvtime/speedy.c: (multiply_alpha), (clip255),
(comb_factor_packed422_scanline_mmx),
(diff_factor_packed422_scanline_c),
(diff_factor_packed422_scanline_mmx),
(diff_packed422_block8x8_mmx), (diff_packed422_block8x8_c),
(packed444_to_packed422_scanline_c),
(packed422_to_packed444_scanline_c),
(packed422_to_packed444_rec601_scanline_c),
(vfilter_chroma_121_packed422_scanline_mmx),
(vfilter_chroma_121_packed422_scanline_c),
(vfilter_chroma_332_packed422_scanline_mmx),
(vfilter_chroma_332_packed422_scanline_c),
(kill_chroma_packed422_inplace_scanline_mmx),
(kill_chroma_packed422_inplace_scanline_c),
(invert_colour_packed422_inplace_scanline_mmx),
(invert_colour_packed422_inplace_scanline_c),
(mirror_packed422_inplace_scanline_c),
(interpolate_packed422_scanline_c),
(convert_uyvy_to_yuyv_scanline_mmx),
(convert_uyvy_to_yuyv_scanline_c),
(interpolate_packed422_scanline_mmx),
(interpolate_packed422_scanline_mmxext),
(blit_colour_packed422_scanline_c),
(blit_colour_packed422_scanline_mmx),
(blit_colour_packed422_scanline_mmxext),
(blit_colour_packed4444_scanline_c),
(blit_colour_packed4444_scanline_mmx),
(blit_colour_packed4444_scanline_mmxext), (small_memcpy),
(speedy_memcpy_c), (speedy_memcpy_mmx), (speedy_memcpy_mmxext),
(blit_packed422_scanline_c), (blit_packed422_scanline_mmx),
(blit_packed422_scanline_mmxext),
(composite_colour4444_alpha_to_packed422_scanline_c),
(composite_colour4444_alpha_to_packed422_scanline_mmxext),
(composite_packed4444_alpha_to_packed422_scanline_c),
(composite_packed4444_alpha_to_packed422_scanline_mmxext),
(composite_packed4444_to_packed422_scanline_c),
(composite_packed4444_to_packed422_scanline_mmxext),
(composite_alphamask_to_packed4444_scanline_c),
(composite_alphamask_to_packed4444_scanline_mmxext),
(composite_alphamask_alpha_to_packed4444_scanline_c),
(premultiply_packed4444_scanline_c),
(premultiply_packed4444_scanline_mmxext),
(blend_packed422_scanline_c), (blend_packed422_scanline_mmxext),
(quarter_blit_vertical_packed422_scanline_mmxext),
(quarter_blit_vertical_packed422_scanline_c),
(subpix_blit_vertical_packed422_scanline_c),
(a8_subpix_blit_scanline_c), (myround), (init_RGB_to_YCbCr_tables),
(init_YCbCr_to_RGB_tables), (rgb24_to_packed444_rec601_scanline_c),
(rgba32_to_packed4444_rec601_scanline_c),
(packed444_to_rgb24_rec601_scanline_c),
(packed444_to_nonpremultiplied_packed4444_scanline_c),
(aspect_adjust_packed4444_scanline_c), (setup_speedy_calls),
(speedy_get_accel):
* gst/deinterlace2/tvtime/speedy.h:
* gst/deinterlace2/tvtime/sse.h:
* gst/deinterlace2/tvtime/tomsmocomp.c: (Fieldcopy),
(deinterlace_frame_di_tomsmocomp), (dscaler_tomsmocomp_get_method),
(tomsmocomp_init), (tomsmocomp_filter_mmx),
(tomsmocomp_filter_3dnow), (tomsmocomp_filter_sse):
* gst/deinterlace2/tvtime/tomsmocomp.h:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc:
* gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc:
* gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc:
* gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc:
* gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc:
* gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc:
* gst/deinterlace2/tvtime/vfir.c: (deinterlace_line),
(deinterlace_scanline_vfir), (copy_scanline),
(dscaler_vfir_get_method):
* gst/deinterlace2/tvtime/x86-64_macros.inc:
Add a deinterlacer plugin based on the tvtime/DScaler deinterlacer,
which was relicensed to LGPL for GStreamer and in theory provides
better and faster results than the simple deinterlace element.
Fixes bug #163578.
Ported to GStreamer 0.10 but still not enabled or included in the
build system by default because of bad artefacts caused by a bug
somewhere and as it can be only build on x86/amd64 ATM and requires
special CFLAGS. Will be fixed soon.
This commit is contained in:
Martin Eikermann 2008-06-11 11:12:14 +00:00 committed by Sebastian Dröge
parent 2a362d14c5
commit 0518c150c9
18 changed files with 7411 additions and 0 deletions

View file

@ -0,0 +1,46 @@
plugin_LTLIBRARIES = libgstdeinterlace2.la
libgstdeinterlace2_la_SOURCES = \
gstdeinterlace2.c \
tvtime/greedy.c \
tvtime/greedyh.asm \
tvtime/greedyh.c \
tvtime/speedy.c \
tvtime/vfir.c \
tvtime/x86-64_macros.inc \
tvtime/tomsmocomp.c \
tvtime/tomsmocomp/SearchLoop0A.inc \
tvtime/tomsmocomp/SearchLoopBottom.inc \
tvtime/tomsmocomp/SearchLoopEdgeA8.inc \
tvtime/tomsmocomp/SearchLoopEdgeA.inc \
tvtime/tomsmocomp/SearchLoopOddA2.inc \
tvtime/tomsmocomp/SearchLoopOddA6.inc \
tvtime/tomsmocomp/SearchLoopOddAH2.inc \
tvtime/tomsmocomp/SearchLoopOddAH.inc \
tvtime/tomsmocomp/SearchLoopOddA.inc \
tvtime/tomsmocomp/SearchLoopTop.inc \
tvtime/tomsmocomp/SearchLoopVAH.inc \
tvtime/tomsmocomp/SearchLoopVA.inc \
tvtime/tomsmocomp/StrangeBob.inc \
tvtime/tomsmocomp/TomsMoCompAll2.inc \
tvtime/tomsmocomp/TomsMoCompAll.inc \
tvtime/tomsmocomp/tomsmocompmacros.h \
tvtime/tomsmocomp/WierdBob.inc
libgstdeinterlace2_la_CFLAGS = $(GST_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(LIBOIL_CFLAGS) -march=athlon-xp
libgstdeinterlace2_la_LIBADD = $(GST_LIBS) \
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(LIBOIL_LIBS)
libgstdeinterlace2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = \
gstdeinterlace2.h \
tvtime/mmx.h \
tvtime/sse.h \
tvtime/greedyh.h \
tvtime/greedyhmacros.h \
tvtime/plugins.h \
tvtime/speedtools.h \
tvtime/speedy.h \
tvtime/tomsmocomp.h

View file

@ -0,0 +1,893 @@
/*
* GStreamer
* Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
* Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstdeinterlace2.h"
#include <gst/gst.h>
#include <gst/video/video.h>
#include "tvtime/plugins.h"
#include "tvtime/speedy.h"
GST_DEBUG_CATEGORY_STATIC (deinterlace2_debug);
#define GST_CAT_DEFAULT (deinterlace2_debug)
/* Object signals and args */
enum
{
LAST_SIGNAL
};
/* Arguments */
enum
{
ARG_0,
ARG_METHOD,
ARG_FIELDS,
ARG_FIELD_LAYOUT
};
#define GST_TYPE_DEINTERLACE2_METHOD (gst_deinterlace2_method_get_type ())
static GType
gst_deinterlace2_method_get_type (void)
{
static GType deinterlace2_method_type = 0;
static const GEnumValue method_types[] = {
{GST_DEINTERLACE2_TOM, "Toms Motion Compensation", "tomsmc"},
{GST_DEINTERLACE2_GREEDY_H, "Greedy High Motion", "greedyh"},
{GST_DEINTERLACE2_GREEDY_L, "Greedy Low Motion", "greedyl"},
{GST_DEINTERLACE2_VFIR, "Vertical Blur", "vfir"},
{0, NULL, NULL},
};
if (!deinterlace2_method_type) {
deinterlace2_method_type =
g_enum_register_static ("GstDeinterlace2Methods", method_types);
}
return deinterlace2_method_type;
}
#define GST_TYPE_DEINTERLACE2_FIELDS (gst_deinterlace2_fields_get_type ())
static GType
gst_deinterlace2_fields_get_type (void)
{
static GType deinterlace2_fields_type = 0;
static const GEnumValue fields_types[] = {
{GST_DEINTERLACE2_ALL, "All fields", "all"},
{GST_DEINTERLACE2_TF, "Top fields only", "top"},
{GST_DEINTERLACE2_BF, "Bottom fields only", "bottom"},
{0, NULL, NULL},
};
if (!deinterlace2_fields_type) {
deinterlace2_fields_type =
g_enum_register_static ("GstDeinterlace2Fields", fields_types);
}
return deinterlace2_fields_type;
}
#define GST_TYPE_DEINTERLACE2_FIELD_LAYOUT (gst_deinterlace2_field_layout_get_type ())
static GType
gst_deinterlace2_field_layout_get_type (void)
{
static GType deinterlace2_field_layout_type = 0;
static const GEnumValue field_layout_types[] = {
{GST_DEINTERLACE2_LAYOUT_AUTO, "Auto detection", "auto"},
{GST_DEINTERLACE2_LAYOUT_TFF, "Top field first", "tff"},
{GST_DEINTERLACE2_LAYOUT_BFF, "Bottom field first", "bff"},
{0, NULL, NULL},
};
if (!deinterlace2_field_layout_type) {
deinterlace2_field_layout_type =
g_enum_register_static ("GstDeinterlace2FieldLayout",
field_layout_types);
}
return deinterlace2_field_layout_type;
}
static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2"))
);
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2"))
);
static void gst_deinterlace2_finalize (GObject * object);
static void gst_deinterlace2_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_deinterlace2_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps);
static gboolean gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_deinterlace2_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn gst_deinterlace2_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_deinterlace2_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_deinterlace2_src_query (GstPad * pad, GstQuery * query);
static const GstQueryType *gst_deinterlace2_src_query_types (GstPad * pad);
static void gst_deinterlace2_deinterlace_scanlines (GstDeinterlace2 * object);
GST_BOILERPLATE (GstDeinterlace2, gst_deinterlace2, GstElement,
GST_TYPE_ELEMENT);
static void
gst_deinterlace2_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_templ));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_templ));
gst_element_class_set_details_simple (element_class,
"Deinterlacer",
"Filter/Video",
"Deinterlace Methods ported from DScaler/TvTime",
"Martin Eikermann <meiker@upb.de>, "
"Sebastian Dröge <slomo@circular-chaos.org>");
}
static void
gst_deinterlace2_class_init (GstDeinterlace2Class * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *element_class = (GstElementClass *) klass;
gobject_class->set_property = gst_deinterlace2_set_property;
gobject_class->get_property = gst_deinterlace2_get_property;
gobject_class->finalize = gst_deinterlace2_finalize;
g_object_class_install_property (gobject_class, ARG_METHOD,
g_param_spec_enum ("method",
"Method",
"Deinterlace Method",
GST_TYPE_DEINTERLACE2_METHOD,
GST_DEINTERLACE2_GREEDY_H, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
);
g_object_class_install_property (gobject_class, ARG_FIELDS,
g_param_spec_enum ("fields",
"fields",
"Fields to use for deinterlacing",
GST_TYPE_DEINTERLACE2_FIELDS,
GST_DEINTERLACE2_ALL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
);
g_object_class_install_property (gobject_class, ARG_FIELDS,
g_param_spec_enum ("tff",
"tff",
"Deinterlace top field first",
GST_TYPE_DEINTERLACE2_FIELD_LAYOUT,
GST_DEINTERLACE2_LAYOUT_AUTO,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
);
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_deinterlace2_change_state);
}
static void
gst_deinterlace2_init (GstDeinterlace2 * object, GstDeinterlace2Class * klass)
{
object->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
gst_pad_set_chain_function (object->sinkpad,
GST_DEBUG_FUNCPTR (gst_deinterlace2_chain));
gst_pad_set_event_function (object->sinkpad,
GST_DEBUG_FUNCPTR (gst_deinterlace2_sink_event));
gst_pad_set_setcaps_function (object->sinkpad,
GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps));
gst_pad_set_getcaps_function (object->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_element_add_pad (GST_ELEMENT (object), object->sinkpad);
object->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
gst_pad_set_event_function (object->srcpad,
GST_DEBUG_FUNCPTR (gst_deinterlace2_src_event));
gst_pad_set_query_type_function (object->srcpad,
GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query_types));
gst_pad_set_query_function (object->srcpad,
GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query));
gst_pad_set_setcaps_function (object->srcpad,
GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps));
gst_pad_set_getcaps_function (object->srcpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_element_add_pad (GST_ELEMENT (object), object->srcpad);
gst_element_no_more_pads (GST_ELEMENT (object));
object->cpu_feature_flags = oil_cpu_get_flags ();
setup_speedy_calls (object->cpu_feature_flags, 0);
object->pMemcpy = speedy_memcpy;
object->method = dscaler_tomsmocomp_get_method ();
object->history_count = 0;
object->field_layout = GST_DEINTERLACE2_LAYOUT_AUTO;
object->out_buf = NULL;
object->output_stride = 0;
object->line_length = 0;
object->frame_width = 0;
object->frame_height = 0;
object->field_height = 0;
object->field_stride = 0;
object->fields = GST_DEINTERLACE2_ALL;
object->bottom_field = TRUE;
}
static void
gst_deinterlace2_set_method (GstDeinterlace2 * object,
GstDeinterlace2Methods method)
{
switch (method) {
case GST_DEINTERLACE2_TOM:
object->method_id = method;
object->method = dscaler_tomsmocomp_get_method ();
break;
case GST_DEINTERLACE2_GREEDY_H:
object->method_id = method;
object->method = dscaler_greedyh_get_method ();
break;
case GST_DEINTERLACE2_GREEDY_L:
object->method_id = method;
object->method = dscaler_greedyl_get_method ();
break;
case GST_DEINTERLACE2_VFIR:
object->method_id = method;
object->method = dscaler_vfir_get_method ();
break;
default:
GST_WARNING ("Invalid Deinterlacer Method");
}
if (object->method->deinterlace_frame == NULL)
object->method->deinterlace_frame = gst_deinterlace2_deinterlace_scanlines;
/* TODO: if current method requires less fields in the history,
pop the diff from field_history.
*/
}
static void
gst_deinterlace2_set_property (GObject * _object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDeinterlace2 *object;
g_return_if_fail (GST_IS_DEINTERLACE2 (_object));
object = GST_DEINTERLACE2 (_object);
switch (prop_id) {
case ARG_METHOD:
gst_deinterlace2_set_method (object, g_value_get_enum (value));
break;
case ARG_FIELDS:
object->fields = g_value_get_enum (value);
break;
case ARG_FIELD_LAYOUT:
object->field_layout = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gst_deinterlace2_get_property (GObject * _object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDeinterlace2 *object;
g_return_if_fail (GST_IS_DEINTERLACE2 (_object));
object = GST_DEINTERLACE2 (_object);
switch (prop_id) {
case ARG_METHOD:
g_value_set_enum (value, object->method_id);
break;
case ARG_FIELDS:
g_value_set_enum (value, object->fields);
break;
case ARG_FIELD_LAYOUT:
g_value_set_enum (value, object->field_layout);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gst_deinterlace2_finalize (GObject * object)
{
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static GstBuffer *
gst_deinterlace2_pop_history (GstDeinterlace2 * object)
{
GstBuffer *buffer = NULL;
g_assert (object->history_count > 0);
buffer = object->field_history[object->history_count - 1].buf;
object->history_count--;
GST_DEBUG ("pop, size(history): %d", object->history_count);
return buffer;
}
#if 0
static GstBuffer *
gst_deinterlace2_head_history (GstDeinterlace2 * object)
{
return object->field_history[object->history_count - 1].buf;
}
#endif
/* invariant: field with smallest timestamp is object->field_history[object->history_count-1]
*/
static void
gst_deinterlace2_push_history (GstDeinterlace2 * object, GstBuffer * buffer)
{
int i = 1;
GstClockTime timestamp;
GstClockTime field_diff;
g_assert (object->history_count < MAX_FIELD_HISTORY - 2);
for (i = MAX_FIELD_HISTORY - 1; i >= 2; i--) {
object->field_history[i].buf = object->field_history[i - 2].buf;
object->field_history[i].flags = object->field_history[i - 2].flags;
}
if (object->field_layout == GST_DEINTERLACE2_LAYOUT_AUTO) {
GST_WARNING ("Could not detect field layout. Assuming top field first.");
object->field_layout = GST_DEINTERLACE2_LAYOUT_TFF;
}
if (object->field_layout == GST_DEINTERLACE2_LAYOUT_TFF) {
GST_DEBUG ("Top field first");
object->field_history[0].buf =
gst_buffer_create_sub (buffer, object->line_length,
GST_BUFFER_SIZE (buffer) - object->line_length);
object->field_history[0].flags = PICTURE_INTERLACED_BOTTOM;
object->field_history[1].buf = buffer;
object->field_history[1].flags = PICTURE_INTERLACED_TOP;
} else {
GST_DEBUG ("Bottom field first");
object->field_history[0].buf = buffer;
object->field_history[0].flags = PICTURE_INTERLACED_TOP;
object->field_history[1].buf =
gst_buffer_create_sub (buffer, object->line_length,
GST_BUFFER_SIZE (buffer) - object->line_length);
object->field_history[1].flags = PICTURE_INTERLACED_BOTTOM;
}
/* Timestamps are assigned to the field buffers under the assumption that
the timestamp of the buffer equals the first fields timestamp */
timestamp = GST_BUFFER_TIMESTAMP (buffer);
field_diff = GST_SECOND / (object->frame_rate_d * 2) / object->frame_rate_n;
GST_BUFFER_TIMESTAMP (object->field_history[0].buf) = timestamp + field_diff;
GST_BUFFER_TIMESTAMP (object->field_history[1].buf) = timestamp;
object->history_count += 2;
GST_DEBUG ("push, size(history): %d", object->history_count);
}
/* some methods support only deinterlace_/copy_scanline functions.
This funtion calls them in the right manner. */
static void
gst_deinterlace2_deinterlace_scanlines (GstDeinterlace2 * object)
{
gint line = 1;
gint cur_field_idx = object->history_count - object->method->fields_required;
GST_INFO ("cur_field_idx: %d", cur_field_idx);
guint8 *out_data = GST_BUFFER_DATA (object->out_buf);
guint8 *cur_field =
GST_BUFFER_DATA (object->field_history[cur_field_idx].buf);
guint8 *last_field = NULL;
guint8 *second_last_field = NULL;
/* method can just handle up to 3 history fields,
bcs until now there isn't a plugin (with interp./copy scanline methods)
that uses more */
g_assert (object->method->fields_required <= 3);
if (object->method->fields_required >= 2) {
last_field = GST_BUFFER_DATA (object->field_history[cur_field_idx + 1].buf);
}
if (object->method->fields_required >= 3) {
second_last_field =
GST_BUFFER_DATA (object->field_history[cur_field_idx + 2].buf);
}
if (object->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM) {
/* double the first scanline of the bottom field */
blit_packed422_scanline (out_data, cur_field, object->frame_width);
out_data += object->output_stride;
}
blit_packed422_scanline (out_data, cur_field, object->frame_width);
out_data += object->output_stride;
line++;
for (; line <= object->field_height;) {
deinterlace_scanline_data_t data;
/* interp. scanline */
data.t0 = cur_field;
data.b0 = cur_field + object->field_stride;
if (last_field != NULL) {
data.tt1 = last_field;
data.m1 = last_field + object->field_stride;
data.bb1 = last_field + (object->field_stride * 2);
last_field += object->field_stride;
}
if (second_last_field != NULL) {
data.t2 = second_last_field;
data.b2 = second_last_field + object->field_stride;
}
/* set valid data for corner cases */
if (line == 2) {
data.tt1 = data.bb1;
} else if (line == object->field_height) {
data.bb1 = data.tt1;
}
object->method->interpolate_scanline (object, &data, out_data);
out_data += object->output_stride;
/* copy a scanline */
data.tt0 = cur_field;
data.m0 = cur_field + (object->field_stride);
data.bb0 = cur_field + (object->field_stride * 2);
cur_field += object->field_stride;
if (last_field != NULL) {
data.t1 = last_field;
data.b1 = last_field + object->field_stride;
}
if (second_last_field != NULL) {
data.tt2 = second_last_field;
data.m2 = second_last_field + (object->field_stride);
data.bb2 = second_last_field + (object->field_stride * 2);
second_last_field += object->field_stride;
}
/* set valid data for corner cases */
if (line == object->field_height) {
data.bb0 = data.tt0;
data.bb2 = data.tt2;
data.b1 = data.t1;
}
object->method->copy_scanline (object, &data, out_data);
out_data += object->output_stride;
line++;
}
if (object->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP) {
/* double the last scanline of the top field */
blit_packed422_scanline (out_data, cur_field, object->frame_width);
}
}
static GstFlowReturn
gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf)
{
//GstBuffer *out_buf = NULL;
GstDeinterlace2 *object = NULL;
GstClockTime timestamp;
//GstFlowReturn ret = GST_FLOW_OK;
object = GST_DEINTERLACE2 (GST_PAD_PARENT (pad));
gst_deinterlace2_push_history (object, buf);
buf = NULL;
if (object->method != NULL) {
int cur_field_idx = 0;
/* Not enough fields in the history */
if (object->history_count < object->method->fields_required + 1) {
/* TODO: do bob or just forward frame */
GST_DEBUG ("HistoryCount=%d", object->history_count);
return GST_FLOW_OK;
}
if (object->fields == GST_DEINTERLACE2_ALL)
GST_DEBUG ("All fields");
if (object->fields == GST_DEINTERLACE2_TF)
GST_DEBUG ("Top fields");
if (object->fields == GST_DEINTERLACE2_BF)
GST_DEBUG ("Bottom fields");
cur_field_idx = object->history_count - object->method->fields_required;
if ((object->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
&& object->fields == GST_DEINTERLACE2_TF) ||
object->fields == GST_DEINTERLACE2_ALL) {
GST_DEBUG ("deinterlacing top field");
/* create new buffer */
object->out_buf = gst_buffer_new_and_alloc (object->frame_size);
gst_buffer_set_caps (object->out_buf, GST_PAD_CAPS (object->srcpad));
/* do magic calculus */
if (object->method->deinterlace_frame != NULL) {
object->method->deinterlace_frame (object);
buf = gst_deinterlace2_pop_history (object);
timestamp = GST_BUFFER_TIMESTAMP (buf);
gst_buffer_unref (buf);
GST_BUFFER_TIMESTAMP (object->out_buf) = timestamp;
gst_pad_push (object->srcpad, object->out_buf);
}
}
/* no calculation done: remove excess field */
else if (object->field_history[cur_field_idx].flags ==
PICTURE_INTERLACED_TOP && object->fields == GST_DEINTERLACE2_BF) {
GST_DEBUG ("Removing unused top field");
buf = gst_deinterlace2_pop_history (object);
gst_buffer_unref (buf);
}
cur_field_idx = object->history_count - object->method->fields_required;
/* deinterlace bottom_field */
if ((object->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
&& object->fields == GST_DEINTERLACE2_BF) ||
object->fields == GST_DEINTERLACE2_ALL) {
GST_DEBUG ("deinterlacing bottom field");
/* create new buffer */
object->out_buf = gst_buffer_new_and_alloc (object->frame_size);
gst_buffer_set_caps (object->out_buf, GST_PAD_CAPS (object->srcpad));
/* do magic calculus */
if (object->method->deinterlace_frame != NULL) {
object->method->deinterlace_frame (object);
buf = gst_deinterlace2_pop_history (object);
timestamp = GST_BUFFER_TIMESTAMP (buf);
gst_buffer_unref (buf);
GST_BUFFER_TIMESTAMP (object->out_buf) = timestamp;
gst_pad_push (object->srcpad, object->out_buf);
}
}
/* no calculation done: remove excess field */
else if (object->field_history[cur_field_idx].flags ==
PICTURE_INTERLACED_BOTTOM && object->fields == GST_DEINTERLACE2_TF) {
GST_DEBUG ("Removing unused bottom field");
buf = gst_deinterlace2_pop_history (object);
gst_buffer_unref (buf);
}
} else {
object->out_buf = gst_deinterlace2_pop_history (object);
gst_pad_push (object->srcpad, object->out_buf);
}
GST_DEBUG ("----chain end ----\n\n");
return GST_FLOW_OK;
}
static gboolean
gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps)
{
gboolean res = TRUE;
GstDeinterlace2 *object = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
GstPad *otherpad;
GstStructure *structure;
GstVideoFormat fmt;
guint32 fourcc;
otherpad = (pad == object->srcpad) ? object->sinkpad : object->srcpad;
if (!gst_pad_accept_caps (otherpad, caps)
|| !gst_pad_set_caps (otherpad, caps))
goto caps_not_accepted;
structure = gst_caps_get_structure (caps, 0);
res = gst_structure_get_int (structure, "width", &object->frame_width);
res &= gst_structure_get_int (structure, "height", &object->frame_height);
res &=
gst_structure_get_fraction (structure, "framerate", &object->frame_rate_n,
&object->frame_rate_d);
res &= gst_structure_get_fourcc (structure, "format", &fourcc);
/* TODO: get interlaced, field_layout, field_order */
if (!res)
goto invalid_caps;
/* TODO: introduce object->field_stride */
object->field_height = object->frame_height / 2;
fmt = gst_video_format_from_fourcc (fourcc);
/* TODO: only true if fields are subbuffers of interlaced frames,
change when the buffer-fields concept has landed */
object->field_stride =
gst_video_format_get_row_stride (fmt, 0, object->frame_width) * 2;
object->output_stride =
gst_video_format_get_row_stride (fmt, 0, object->frame_width);
/* in bytes */
object->line_length =
gst_video_format_get_row_stride (fmt, 0, object->frame_width);
object->frame_size =
gst_video_format_get_size (fmt, object->frame_width,
object->frame_height);
GST_DEBUG_OBJECT (object, "Set caps: %" GST_PTR_FORMAT, caps);
done:
gst_object_unref (object);
return res;
invalid_caps:
res = FALSE;
GST_ERROR_OBJECT (object, "Invalid caps: %" GST_PTR_FORMAT, caps);
goto done;
caps_not_accepted:
res = FALSE;
GST_ERROR_OBJECT (object, "Caps not accepted: %" GST_PTR_FORMAT, caps);
goto done;
}
static gboolean
gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event)
{
gboolean res = TRUE;
GstDeinterlace2 *object = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
case GST_EVENT_EOS:
case GST_EVENT_NEWSEGMENT:
/* TODO: reset history */
/* fall through */
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (object);
return res;
}
static GstStateChangeReturn
gst_deinterlace2_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret != GST_STATE_CHANGE_SUCCESS)
return ret;
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* TODO: reset history, clean up, etc */
break;
case GST_STATE_CHANGE_READY_TO_NULL:
default:
break;
}
return ret;
}
static gboolean
gst_deinterlace2_src_event (GstPad * pad, GstEvent * event)
{
GstDeinterlace2 *object = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
gboolean res;
GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (object);
return res;
}
static gboolean
gst_deinterlace2_src_query (GstPad * pad, GstQuery * query)
{
GstDeinterlace2 *object = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
gboolean res = FALSE;
GST_LOG_OBJECT (object, "%s query", GST_QUERY_TYPE_NAME (query));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:
{
GstClockTime min, max;
gboolean live;
GstPad *peer;
if ((peer = gst_pad_get_peer (object->sinkpad))) {
if ((res = gst_pad_query (peer, query))) {
GstClockTime latency;
gst_query_parse_latency (query, &live, &min, &max);
GST_DEBUG ("Peer latency: min %"
GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
GST_TIME_ARGS (min), GST_TIME_ARGS (max));
/* TODO: calculate our own latency from framerate
* and object->method->fields_required */
/* add our own latency */
latency =
gst_util_uint64_scale (object->method->fields_required *
GST_SECOND, object->frame_rate_d, object->frame_rate_n);
GST_DEBUG ("Our latency: min %" GST_TIME_FORMAT
", max %" GST_TIME_FORMAT,
GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
min += latency;
if (max != GST_CLOCK_TIME_NONE)
max += latency;
else
max = latency;
GST_DEBUG ("Calculated total latency : min %"
GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
GST_TIME_ARGS (min), GST_TIME_ARGS (max));
gst_query_set_latency (query, live, min, max);
}
gst_object_unref (peer);
}
break;
}
default:
res = gst_pad_query_default (pad, query);
break;
}
gst_object_unref (object);
return res;
}
static const GstQueryType *
gst_deinterlace2_src_query_types (GstPad * pad)
{
static const GstQueryType types[] = {
GST_QUERY_LATENCY,
GST_QUERY_NONE
};
return types;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (deinterlace2_debug, "deinterlace2", 0,
"Deinterlacer");
oil_init ();
if (!gst_element_register (plugin, "deinterlace2", GST_RANK_NONE,
GST_TYPE_DEINTERLACE2)) {
return FALSE;
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"deinterlace2",
"Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
GST_PACKAGE_ORIGIN);

View file

@ -0,0 +1,267 @@
/*
* GStreamer
* Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
* Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_DEINTERLACE_2_H__
#define __GST_DEINTERLACE_2_H__
#include <liboil/liboil.h>
#include <liboil/liboilfunction.h>
#include <liboil/liboilcpu.h>
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
G_BEGIN_DECLS
#define GST_TYPE_DEINTERLACE2 \
(gst_deinterlace2_get_type())
#define GST_DEINTERLACE2(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLACE2,GstDeinterlace2))
#define GST_DEINTERLACE2_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLACE2,GstDeinterlace2))
#define GST_IS_DEINTERLACE2(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE2))
#define GST_IS_DEINTERLACE2_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE2))
typedef struct _GstDeinterlace2 GstDeinterlace2;
typedef struct _GstDeinterlace2Class GstDeinterlace2Class;
typedef struct deinterlace_setting_s deinterlace_setting_t;
typedef struct deinterlace_method_s deinterlace_method_t;
typedef struct deinterlace_scanline_data_s deinterlace_scanline_data_t;
typedef struct deinterlace_frame_data_s deinterlace_frame_data_t;
/**
* There are two scanline functions that every deinterlacer plugin
* must implement to do its work: one for a 'copy' and one for
* an 'interpolate' for the currently active field. This so so that
* while plugins may be delaying fields, the external API assumes that
* the plugin is completely realtime.
*
* Each deinterlacing routine can require data from up to four fields.
* The most recent field captured is field 0, and increasing numbers go
* backwards in time.
*/
struct deinterlace_scanline_data_s
{
guint8 *tt0, *t0, *m0, *b0, *bb0;
guint8 *tt1, *t1, *m1, *b1, *bb1;
guint8 *tt2, *t2, *m2, *b2, *bb2;
guint8 *tt3, *t3, *m3, *b3, *bb3;
int bottom_field;
};
/**
* | t-3 t-2 t-1 t
* | Field 3 | Field 2 | Field 1 | Field 0 |
* | TT3 | | TT1 | |
* | | T2 | | T0 |
* | M3 | | M1 | |
* | | B2 | | B0 |
* | BB3 | | BB1 | |
*
* While all pointers are passed in, each plugin is only guarenteed for
* the ones it indicates it requires (in the fields_required parameter)
* to be available.
*
* Pointers are always to scanlines in the standard packed 4:2:2 format.
*/
typedef void (*deinterlace_interp_scanline_t) (GstDeinterlace2 * object,
deinterlace_scanline_data_t * data, guint8 * output);
/**
* For the copy scanline, the API is basically the same, except that
* we're given a scanline to 'copy'.
*
* | t-3 t-2 t-1 t
* | Field 3 | Field 2 | Field 1 | Field 0 |
* | | TT2 | | TT0 |
* | T3 | | T1 | |
* | | M2 | | M0 |
* | B3 | | B1 | |
* | | BB2 | | BB0 |
*/
typedef void (*deinterlace_copy_scanline_t) (GstDeinterlace2 * object,
deinterlace_scanline_data_t * data, guint8 * output);
/**
* The frame function is for deinterlacing plugins that can only act
* on whole frames, rather than on a scanline at a time.
*/
struct deinterlace_frame_data_s
{
guint8 *f0;
guint8 *f1;
guint8 *f2;
guint8 *f3;
};
typedef void (*deinterlace_frame_t) (GstDeinterlace2 * object);
/**
* This structure defines the deinterlacer plugin.
*/
struct deinterlace_method_s
{
int version;
const char *name;
const char *short_name;
int fields_required;
int accelrequired;
int doscalerbob;
int numsettings;
deinterlace_setting_t *settings;
int scanlinemode;
deinterlace_interp_scanline_t interpolate_scanline;
deinterlace_copy_scanline_t copy_scanline;
deinterlace_frame_t deinterlace_frame;
const char *description[10];
};
/**
* Registers a new deinterlace method.
*/
void register_deinterlace_method (deinterlace_method_t * method);
/**
* Returns how many deinterlacing methods are available.
*/
int get_num_deinterlace_methods (void);
/**
* Returns the specified method in the list.
*/
deinterlace_method_t *get_deinterlace_method (int i);
/**
* Builds the usable method list.
*/
void filter_deinterlace_methods (int accel, int fieldsavailable);
#define MAX_FIELD_HISTORY 10
#define PICTURE_PROGRESSIVE 0
#define PICTURE_INTERLACED_BOTTOM 1
#define PICTURE_INTERLACED_TOP 2
#define PICTURE_INTERLACED_MASK (PICTURE_INTERLACED_BOTTOM | PICTURE_INTERLACED_TOP)
typedef void (MEMCPY_FUNC) (void *pOutput, const void *pInput, size_t nSize);
typedef struct
{
/* pointer to the start of data for this field */
GstBuffer *buf;
/* see PICTURE_ flags */
guint flags;
} GstPicture;
typedef enum
{
GST_DEINTERLACE2_TOM,
GST_DEINTERLACE2_GREEDY_H,
GST_DEINTERLACE2_GREEDY_L,
GST_DEINTERLACE2_VFIR
} GstDeinterlace2Methods;
typedef enum
{
GST_DEINTERLACE2_ALL, /* All (missing data is interp.) */
GST_DEINTERLACE2_TF, /* Top Fields Only */
GST_DEINTERLACE2_BF /* Bottom Fields Only */
} GstDeinterlace2Fields;
typedef enum
{
GST_DEINTERLACE2_LAYOUT_AUTO,
GST_DEINTERLACE2_LAYOUT_TFF,
GST_DEINTERLACE2_LAYOUT_BFF
} GstDeinterlace2FieldLayout;
struct _GstDeinterlace2
{
GstElement parent;
GstPad *srcpad, *sinkpad;
guint history_count;
guint cpu_feature_flags;
GstDeinterlace2FieldLayout field_layout;
guint frame_size;
gint frame_rate_n, frame_rate_d;
GstDeinterlace2Fields fields;
GstDeinterlace2Methods method_id;
deinterlace_method_t *method;
/* The most recent pictures
PictureHistory[0] is always the most recent.
Pointers are NULL if the picture in question isn't valid, e.g. because
the program just started or a picture was skipped.
*/
GstPicture field_history[MAX_FIELD_HISTORY];
/* Current overlay buffer pointer. */
GstBuffer *out_buf;
/* Overlay pitch (number of bytes between scanlines). */
guint output_stride;
/* Number of bytes of actual data in each scanline. May be less than
OverlayPitch since the overlay's scanlines might have alignment
requirements. Generally equal to FrameWidth * 2.
*/
guint line_length;
/* Number of pixels in each scanline. */
gint frame_width;
/* Number of scanlines per frame. */
gint frame_height;
/* Number of scanlines per field. FrameHeight / 2, mostly for
cleanliness so we don't have to keep dividing FrameHeight by 2.
*/
gint field_height;
/* Function pointer to optimized memcpy function */
MEMCPY_FUNC *pMemcpy;
/* distance between lines in image
need not match the pixel width
*/
guint field_stride;
gboolean bottom_field;
};
struct _GstDeinterlace2Class
{
GstElementClass parent_class;
};
GType gst_deinterlace2_get_type (void);
G_END_DECLS
#endif /* __GST_DEINTERLACE_2_H__ */

View file

@ -0,0 +1,207 @@
/*
*
* GStreamer
* Copyright (c) 2000 Tom Barry All rights reserved.
* mmx.h port copyright (c) 2002 Billy Biggs <vektor@dumbterm.net>.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry
* and Billy Biggs.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#include <stdio.h>
#if defined (__SVR4) && defined (__sun)
# include <sys/int_types.h>
#else
# include <stdint.h>
#endif
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "mmx.h"
#include "sse.h"
#include "gstdeinterlace2.h"
#include "speedtools.h"
#include "speedy.h"
// This is a simple lightweight DeInterlace method that uses little CPU time
// but gives very good results for low or intermedite motion.
// It defers frames by one field, but that does not seem to produce noticeable
// lip sync problems.
//
// The method used is to take either the older or newer weave pixel depending
// upon which give the smaller comb factor, and then clip to avoid large damage
// when wrong.
//
// I'd intended this to be part of a larger more elaborate method added to
// Blended Clip but this give too good results for the CPU to ignore here.
static void
copy_scanline (GstDeinterlace2 * object,
deinterlace_scanline_data_t * data, uint8_t * output)
{
blit_packed422_scanline (output, data->m1, object->frame_width);
}
static int GreedyMaxComb = 15;
static void
deinterlace_greedy_packed422_scanline_mmxext (GstDeinterlace2 * object,
deinterlace_scanline_data_t * data, uint8_t * output)
{
#ifdef HAVE_CPU_I386
mmx_t MaxComb;
uint8_t *m0 = data->m0;
uint8_t *t1 = data->t1;
uint8_t *b1 = data->b1;
uint8_t *m2 = data->m2;
int width = object->frame_width;
// How badly do we let it weave? 0-255
MaxComb.ub[0] = GreedyMaxComb;
MaxComb.ub[1] = GreedyMaxComb;
MaxComb.ub[2] = GreedyMaxComb;
MaxComb.ub[3] = GreedyMaxComb;
MaxComb.ub[4] = GreedyMaxComb;
MaxComb.ub[5] = GreedyMaxComb;
MaxComb.ub[6] = GreedyMaxComb;
MaxComb.ub[7] = GreedyMaxComb;
// L2 == m0
// L1 == t1
// L3 == b1
// LP2 == m2
width /= 4;
while (width--) {
movq_m2r (*t1, mm1); // L1
movq_m2r (*m0, mm2); // L2
movq_m2r (*b1, mm3); // L3
movq_m2r (*m2, mm0); // LP2
// average L1 and L3 leave result in mm4
movq_r2r (mm1, mm4); // L1
pavgb_r2r (mm3, mm4); // (L1 + L3)/2
// get abs value of possible L2 comb
movq_r2r (mm2, mm7); // L2
psubusb_r2r (mm4, mm7); // L2 - avg
movq_r2r (mm4, mm5); // avg
psubusb_r2r (mm2, mm5); // avg - L2
por_r2r (mm7, mm5); // abs(avg-L2)
movq_r2r (mm4, mm6); // copy of avg for later
// get abs value of possible LP2 comb
movq_r2r (mm0, mm7); // LP2
psubusb_r2r (mm4, mm7); // LP2 - avg
psubusb_r2r (mm0, mm4); // avg - LP2
por_r2r (mm7, mm4); // abs(avg-LP2)
// use L2 or LP2 depending upon which makes smaller comb
psubusb_r2r (mm5, mm4); // see if it goes to zero
psubusb_r2r (mm5, mm5); // 0
pcmpeqb_r2r (mm5, mm4); // if (mm4=0) then FF else 0
pcmpeqb_r2r (mm4, mm5); // opposite of mm4
// if Comb(LP2) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
pand_r2r (mm2, mm5); // use L2 if mm5 == ff, else 0
pand_r2r (mm0, mm4); // use LP2 if mm4 = ff, else 0
por_r2r (mm5, mm4); // may the best win
// Now lets clip our chosen value to be not outside of the range
// of the high/low range L1-L3 by more than abs(L1-L3)
// This allows some comb but limits the damages and also allows more
// detail than a boring oversmoothed clip.
movq_r2r (mm1, mm2); // copy L1
psubusb_r2r (mm3, mm2); // - L3, with saturation
paddusb_r2r (mm3, mm2); // now = Max(L1,L3)
pcmpeqb_r2r (mm7, mm7); // all ffffffff
psubusb_r2r (mm1, mm7); // - L1
paddusb_r2r (mm7, mm3); // add, may sat at fff..
psubusb_r2r (mm7, mm3); // now = Min(L1,L3)
// allow the value to be above the high or below the low by amt of MaxComb
paddusb_m2r (MaxComb, mm2); // increase max by diff
psubusb_m2r (MaxComb, mm3); // lower min by diff
psubusb_r2r (mm3, mm4); // best - Min
paddusb_r2r (mm3, mm4); // now = Max(best,Min(L1,L3)
pcmpeqb_r2r (mm7, mm7); // all ffffffff
psubusb_r2r (mm4, mm7); // - Max(best,Min(best,L3)
paddusb_r2r (mm7, mm2); // add may sat at FFF..
psubusb_r2r (mm7, mm2); // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
movntq_r2m (mm2, *output); // move in our clipped best
// Advance to the next set of pixels.
output += 8;
m0 += 8;
t1 += 8;
b1 += 8;
m2 += 8;
}
sfence ();
emms ();
#endif
}
static deinterlace_method_t greedyl_method = {
0, //DEINTERLACE_PLUGIN_API_VERSION,
"Motion Adaptive: Simple Detection",
"AdaptiveSimple",
3,
OIL_IMPL_FLAG_MMXEXT,
0,
0,
0,
1,
copy_scanline,
deinterlace_greedy_packed422_scanline_mmxext,
0,
{"Uses heuristics to detect motion in the input",
"frames and reconstruct image detail where",
"possible. Use this for high quality output",
"even on monitors set to an arbitrary refresh",
"rate.",
"",
"Simple detection uses linear interpolation",
"where motion is detected, using a two-field",
"buffer. This is the Greedy: Low Motion",
"deinterlacer from DScaler."}
};
deinterlace_method_t *
dscaler_greedyl_get_method (void)
{
return &greedyl_method;
}

View file

@ -0,0 +1,307 @@
/*
*
* GStreamer
* Copyright (c) 2001 Tom Barry. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#include "x86-64_macros.inc"
void FUNCT_NAME( GstDeinterlace2 *object)
{
int64_t i;
int InfoIsOdd = 0;
// in tight loop some vars are accessed faster in local storage
int64_t YMask = 0x00ff00ff00ff00ffull; // to keep only luma
int64_t UVMask = 0xff00ff00ff00ff00ull; // to keep only chroma
int64_t ShiftMask = 0xfefffefffefffeffull; // to avoid shifting chroma to luma
int64_t QW256 = 0x0100010001000100ull; // 4 256's
// Set up our two parms that are actually evaluated for each pixel
i=GreedyMaxComb;
int64_t MaxComb = i << 56 | i << 48 | i << 40 | i << 32 | i << 24 | i << 16 | i << 8 | i;
i = GreedyMotionThreshold; // scale to range of 0-257
int64_t MotionThreshold = i << 48 | i << 32 | i << 16 | i | UVMask;
i = GreedyMotionSense; // scale to range of 0-257
int64_t MotionSense = i << 48 | i << 32 | i << 16 | i;
int Line;
long LoopCtr;
unsigned int Pitch = object->field_stride;
unsigned char* L1; // ptr to Line1, of 3
unsigned char* L2; // ptr to Line2, the weave line
unsigned char* L3; // ptr to Line3
unsigned char* L2P; // ptr to prev Line2
unsigned char* Dest = GST_BUFFER_DATA(object->out_buf);
int64_t QW256B;
int64_t LastAvg=0; //interp value from left qword
i = 0xffffffff - 256;
QW256B = i << 48 | i << 32 | i << 16 | i; // save a couple instr on PMINSW instruct.
// copy first even line no matter what, and the first odd line if we're
// processing an EVEN field. (note diff from other deint rtns.)
if (object->field_history[object->history_count-1].flags == PICTURE_INTERLACED_BOTTOM) {
InfoIsOdd = 1;
L1 = GST_BUFFER_DATA(object->field_history[object->history_count-2].buf);
L2 = GST_BUFFER_DATA(object->field_history[object->history_count-1].buf);
L3 = L1 + Pitch;
L2P = GST_BUFFER_DATA(object->field_history[object->history_count-3].buf);
// copy first even line
object->pMemcpy(Dest, L1, object->line_length);
Dest += object->output_stride;
}
else {
InfoIsOdd = 0;
L1 = GST_BUFFER_DATA(object->field_history[object->history_count-2].buf);
L2 = GST_BUFFER_DATA(object->field_history[object->history_count-1].buf) + Pitch;
L3 = L1 + Pitch;
L2P = GST_BUFFER_DATA(object->field_history[object->history_count-3].buf) + Pitch;
// copy first even line
object->pMemcpy(Dest, GST_BUFFER_DATA(object->field_history[0].buf), object->line_length);
Dest += object->output_stride;
// then first odd line
object->pMemcpy(Dest, L1, object->line_length);
Dest += object->output_stride;
}
long oldbx;
for (Line = 0; Line < (object->field_height - 1); ++Line) {
LoopCtr = object->line_length / 8 - 1; // there are LineLength / 8 qwords per line but do 1 less, adj at end of loop
// For ease of reading, the comments below assume that we're operating on an odd
// field (i.e., that InfoIsOdd is true). Assume the obvious for even lines..
__asm__ __volatile__
(
// save ebx (-fPIC)
MOVX" %%"XBX", %[oldbx]\n\t"
MOVX" %[L1], %%"XAX"\n\t"
LEAX" 8(%%"XAX"), %%"XBX"\n\t" // next qword needed by DJR
MOVX" %[L3], %%"XCX"\n\t"
SUBX" %%"XAX", %%"XCX"\n\t" // carry L3 addr as an offset
MOVX" %[L2P], %%"XDX"\n\t"
MOVX" %[L2], %%"XSI"\n\t"
MOVX" %[Dest], %%"XDI"\n\t" // DL1 if Odd or DL2 if Even
".align 8\n\t"
"1:\n\t"
"movq (%%"XSI"), %%mm0\n\t" // L2 - the newest weave pixel value
"movq (%%"XAX"), %%mm1\n\t" // L1 - the top pixel
"movq (%%"XDX"), %%mm2\n\t" // L2P - the prev weave pixel
"movq (%%"XAX", %%"XCX"), %%mm3\n\t" // L3, next odd row
"movq %%mm1, %%mm6\n\t" // L1 - get simple single pixel interp
// pavgb mm6, mm3 // use macro below
V_PAVGB ("%%mm6", "%%mm3", "%%mm4", "%[ShiftMask]")
// DJR - Diagonal Jaggie Reduction
// In the event that we are going to use an average (Bob) pixel we do not want a jagged
// stair step effect. To combat this we avg in the 2 horizontally adjacen pixels into the
// interpolated Bob mix. This will do horizontal smoothing for only the Bob'd pixels.
"movq %[LastAvg], %%mm4\n\t" // the bob value from prev qword in row
"movq %%mm6, %[LastAvg]\n\t" // save for next pass
"psrlq $48, %%mm4\n\t" // right justify 1 pixel
"movq %%mm6, %%mm7\n\t" // copy of simple bob pixel
"psllq $16, %%mm7\n\t" // left justify 3 pixels
"por %%mm7, %%mm4\n\t" // and combine
"movq (%%"XBX"), %%mm5\n\t" // next horiz qword from L1
// pavgb mm5, qword ptr[ebx+ecx] // next horiz qword from L3, use macro below
V_PAVGB ("%%mm5", "(%%"XBX",%%"XCX")", "%%mm7", "%[ShiftMask]")
"psllq $48, %%mm5\n\t" // left just 1 pixel
"movq %%mm6, %%mm7\n\t" // another copy of simple bob pixel
"psrlq $16, %%mm7\n\t" // right just 3 pixels
"por %%mm7, %%mm5\n\t" // combine
// pavgb mm4, mm5 // avg of forward and prev by 1 pixel, use macro
V_PAVGB ("%%mm4", "%%mm5", "%%mm5", "%[ShiftMask]") // mm5 gets modified if MMX
// pavgb mm6, mm4 // avg of center and surround interp vals, use macro
V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
// Don't do any more averaging than needed for mmx. It hurts performance and causes rounding errors.
#ifndef IS_MMX
// pavgb mm4, mm6 // 1/4 center, 3/4 adjacent
V_PAVGB ("%%mm4", "%%mm6", "%%mm7", "%[ShiftMask]")
// pavgb mm6, mm4 // 3/8 center, 5/8 adjacent
V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
#endif
// get abs value of possible L2 comb
"movq %%mm6, %%mm4\n\t" // work copy of interp val
"movq %%mm2, %%mm7\n\t" // L2
"psubusb %%mm4, %%mm7\n\t" // L2 - avg
"movq %%mm4, %%mm5\n\t" // avg
"psubusb %%mm2, %%mm5\n\t" // avg - L2
"por %%mm7, %%mm5\n\t" // abs(avg-L2)
// get abs value of possible L2P comb
"movq %%mm0, %%mm7\n\t" // L2P
"psubusb %%mm4, %%mm7\n\t" // L2P - avg
"psubusb %%mm0, %%mm4\n\t" // avg - L2P
"por %%mm7, %%mm4\n\t" // abs(avg-L2P)
// use L2 or L2P depending upon which makes smaller comb
"psubusb %%mm5, %%mm4\n\t" // see if it goes to zero
"psubusb %%mm5, %%mm5\n\t" // 0
"pcmpeqb %%mm5, %%mm4\n\t" // if (mm4=0) then FF else 0
"pcmpeqb %%mm4, %%mm5\n\t" // opposite of mm4
// if Comb(L2P) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
"pand %%mm2, %%mm5\n\t" // use L2 if mm5 == ff, else 0
"pand %%mm0, %%mm4\n\t" // use L2P if mm4 = ff, else 0
"por %%mm5, %%mm4\n\t" // may the best win
// Inventory: at this point we have the following values:
// mm0 = L2P (or L2)
// mm1 = L1
// mm2 = L2 (or L2P)
// mm3 = L3
// mm4 = the best of L2,L2P weave pixel, base upon comb
// mm6 = the avg interpolated value, if we need to use it
// Let's measure movement, as how much the weave pixel has changed
"movq %%mm2, %%mm7\n\t"
"psubusb %%mm0, %%mm2\n\t"
"psubusb %%mm7, %%mm0\n\t"
"por %%mm2, %%mm0\n\t" // abs value of change, used later
// Now lets clip our chosen value to be not outside of the range
// of the high/low range L1-L3 by more than MaxComb.
// This allows some comb but limits the damages and also allows more
// detail than a boring oversmoothed clip.
"movq %%mm1, %%mm2\n\t" // copy L1
// pmaxub mm2, mm3 // use macro
V_PMAXUB ("%%mm2", "%%mm3") // now = Max(L1,L3)
"movq %%mm1, %%mm5\n\t" // copy L1
// pminub mm5, mm3 // now = Min(L1,L3), use macro
V_PMINUB ("%%mm5", "%%mm3", "%%mm7")
// allow the value to be above the high or below the low by amt of MaxComb
"psubusb %[MaxComb], %%mm5\n\t" // lower min by diff
"paddusb %[MaxComb], %%mm2\n\t" // increase max by diff
// pmaxub mm4, mm5 // now = Max(best,Min(L1,L3) use macro
V_PMAXUB ("%%mm4", "%%mm5")
// pminub mm4, mm2 // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
V_PMINUB ("%%mm4", "%%mm2", "%%mm7")
// Blend weave pixel with bob pixel, depending on motion val in mm0
"psubusb %[MotionThreshold], %%mm0\n\t"// test Threshold, clear chroma change >>>??
"pmullw %[MotionSense], %%mm0\n\t" // mul by user factor, keep low 16 bits
"movq %[QW256], %%mm7\n\t"
#ifdef HAVE_SSE
"pminsw %%mm7, %%mm0\n\t" // max = 256
#else
"paddusw %[QW256B], %%mm0\n\t" // add, may sat at fff..
"psubusw %[QW256B], %%mm0\n\t" // now = Min(L1,256)
#endif
"psubusw %%mm0, %%mm7\n\t" // so the 2 sum to 256, weighted avg
"movq %%mm4, %%mm2\n\t" // save weave chroma info before trashing
"pand %[YMask], %%mm4\n\t" // keep only luma from calc'd value
"pmullw %%mm7, %%mm4\n\t" // use more weave for less motion
"pand %[YMask], %%mm6\n\t" // keep only luma from calc'd value
"pmullw %%mm0, %%mm6\n\t" // use more bob for large motion
"paddusw %%mm6, %%mm4\n\t" // combine
"psrlw $8, %%mm4\n\t" // div by 256 to get weighted avg
// chroma comes from weave pixel
"pand %[UVMask], %%mm2\n\t" // keep chroma
"por %%mm4, %%mm2\n\t" // and combine
V_MOVNTQ ("(%%"XDI")", "%%mm2") // move in our clipped best, use macro
// bump ptrs and loop
LEAX" 8(%%"XAX"), %%"XAX"\n\t"
LEAX" 8(%%"XBX"), %%"XBX"\n\t"
LEAX" 8(%%"XDX"), %%"XDX"\n\t"
LEAX" 8(%%"XDI"), %%"XDI"\n\t"
LEAX" 8(%%"XSI"), %%"XSI"\n\t"
DECX" %[LoopCtr]\n\t"
"jg 1b\n\t" // loop if not to last line
// note P-III default assumes backward branches taken
"jl 1f\n\t" // done
MOVX" %%"XAX", %%"XBX"\n\t" // sharpness lookahead 1 byte only, be wrong on 1
"jmp 1b\n\t"
"1:\n\t"
MOVX" %[oldbx], %%"XBX"\n\t"
: /* no outputs */
: [LastAvg] "m"(LastAvg),
[L1] "m"(L1),
[L3] "m"(L3),
[L2P] "m"(L2P),
[L2] "m"(L2),
[Dest] "m"(Dest),
[ShiftMask] "m"(ShiftMask),
[MaxComb] "m"(MaxComb),
[MotionThreshold] "m"(MotionThreshold),
[MotionSense] "m"(MotionSense),
[QW256B] "m"(QW256B),
[YMask] "m"(YMask),
[UVMask] "m"(UVMask),
[LoopCtr] "m"(LoopCtr),
[QW256] "m"(QW256),
[oldbx] "m"(oldbx)
: XAX, XCX, XDX, XSI, XDI,
#ifdef HAVE_CPU_I386
"st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
#endif
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
"memory", "cc"
);
Dest += object->output_stride;
object->pMemcpy(Dest, L3, object->line_length);
Dest += object->output_stride;
L1 += Pitch;
L2 += Pitch;
L3 += Pitch;
L2P += Pitch;
}
if (InfoIsOdd) {
object->pMemcpy(Dest, L2, object->line_length);
}
// clear out the MMX registers ready for doing floating point again
#ifdef HAVE_CPU_I386
__asm__ __volatile__ ("emms\n\t");
#endif
}

View file

@ -0,0 +1,148 @@
/*
*
* GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "greedyh.h"
#include "greedyhmacros.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "gst/gst.h"
#include "plugins.h"
#include "gstdeinterlace2.h"
#include "speedy.h"
#define MAXCOMB_DEFAULT 5
#define MOTIONTHRESHOLD_DEFAULT 25
#define MOTIONSENSE_DEFAULT 30
unsigned int GreedyMaxComb;
unsigned int GreedyMotionThreshold;
unsigned int GreedyMotionSense;
#define IS_SSE
#define SSE_TYPE SSE
#define FUNCT_NAME greedyDScaler_SSE
#include "greedyh.asm"
#undef SSE_TYPE
#undef IS_SSE
#undef FUNCT_NAME
#define IS_3DNOW
#define FUNCT_NAME greedyDScaler_3DNOW
#define SSE_TYPE 3DNOW
#include "greedyh.asm"
#undef SSE_TYPE
#undef IS_3DNOW
#undef FUNCT_NAME
#define IS_MMX
#define SSE_TYPE MMX
#define FUNCT_NAME greedyDScaler_MMX
#include "greedyh.asm"
#undef SSE_TYPE
#undef IS_MMX
#undef FUNCT_NAME
void
deinterlace_frame_di_greedyh (GstDeinterlace2 * object)
{
if (object->cpu_feature_flags & OIL_IMPL_FLAG_SSE) {
greedyh_filter_sse (object);
} else if (object->cpu_feature_flags & OIL_IMPL_FLAG_3DNOW) {
greedyh_filter_3dnow (object);
} else {
greedyh_filter_mmx (object);
}
}
static deinterlace_method_t greedyh_method = {
0, //DEINTERLACE_PLUGIN_API_VERSION,
"Motion Adaptive: Advanced Detection",
"AdaptiveAdvanced",
4,
OIL_IMPL_FLAG_MMX,
0,
0,
0,
0,
0,
0,
deinterlace_frame_di_greedyh,
{"Uses heuristics to detect motion in the input",
"frames and reconstruct image detail where",
"possible. Use this for high quality output",
"even on monitors set to an arbitrary refresh",
"rate.",
"",
"Advanced detection uses linear interpolation",
"where motion is detected, using a four-field",
"buffer. This is the Greedy: High Motion",
"deinterlacer from DScaler."}
};
deinterlace_method_t *
dscaler_greedyh_get_method (void)
{
greedyh_init ();
return &greedyh_method;
}
void
greedyh_init (void)
{
GreedyMaxComb = MAXCOMB_DEFAULT;
GreedyMotionThreshold = MOTIONTHRESHOLD_DEFAULT;
GreedyMotionSense = MOTIONSENSE_DEFAULT;
}
void
greedyh_filter_mmx (GstDeinterlace2 * object)
{
greedyDScaler_MMX (object);
}
void
greedyh_filter_3dnow (GstDeinterlace2 * object)
{
greedyDScaler_3DNOW (object);
}
void
greedyh_filter_sse (GstDeinterlace2 * object)
{
greedyDScaler_SSE (object);
}

View file

@ -0,0 +1,45 @@
/*
*
* GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#ifndef GREEDYH_H_INCLUDED
#define GREEDYH_H_INCLUDED
#include "gstdeinterlace2.h"
#ifdef __cplusplus
extern "C" {
#endif
void greedyh_init( void );
void greedyh_filter_mmx( GstDeinterlace2 *object );
void greedyh_filter_3dnow( GstDeinterlace2 *object );
void greedyh_filter_sse( GstDeinterlace2 *object );
#ifdef __cplusplus
};
#endif
#endif /* GREEDYH_H_INCLUDED */

View file

@ -0,0 +1,74 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001 Tom Barry. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
//
// This file is subject to the terms of the GNU General Public License as
// published by the Free Software Foundation. A copy of this license is
// included with this software distribution in the file COPYING. If you
// do not have a copy, you may obtain a copy by writing to the Free
// Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
//
// This software 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
//
/////////////////////////////////////////////////////////////////////////////
// Define a few macros for CPU dependent instructions.
// I suspect I don't really understand how the C macro preprocessor works but
// this seems to get the job done. // TRB 7/01
// BEFORE USING THESE YOU MUST SET:
// #define SSE_TYPE SSE (or MMX or 3DNOW)
// some macros for pavgb instruction
// V_PAVGB(mmr1, mmr2, mmr work register, smask) mmr2 may = mmrw if you can trash it
#define V_PAVGB_MMX(mmr1, mmr2, mmrw, smask) \
"movq "mmr2", "mmrw"\n\t" \
"pand "smask", "mmrw"\n\t" \
"psrlw $1, "mmrw"\n\t" \
"pand "smask", "mmr1"\n\t" \
"psrlw $1, "mmr1"\n\t" \
"paddusb "mmrw", "mmr1"\n\t"
#define V_PAVGB_SSE(mmr1, mmr2, mmrw, smask) "pavgb "mmr2", "mmr1"\n\t"
#define V_PAVGB_3DNOW(mmr1, mmr2, mmrw, smask) "pavgusb "mmr2", "mmr1"\n\t"
#define V_PAVGB(mmr1, mmr2, mmrw, smask) V_PAVGB2(mmr1, mmr2, mmrw, smask, SSE_TYPE)
#define V_PAVGB2(mmr1, mmr2, mmrw, smask, ssetyp) V_PAVGB3(mmr1, mmr2, mmrw, smask, ssetyp)
#define V_PAVGB3(mmr1, mmr2, mmrw, smask, ssetyp) V_PAVGB_##ssetyp(mmr1, mmr2, mmrw, smask)
// some macros for pmaxub instruction
#define V_PMAXUB_MMX(mmr1, mmr2) \
"psubusb "mmr2", "mmr1"\n\t" \
"paddusb "mmr2", "mmr1"\n\t"
#define V_PMAXUB_SSE(mmr1, mmr2) "pmaxub "mmr2", "mmr1"\n\t"
#define V_PMAXUB_3DNOW(mmr1, mmr2) V_PMAXUB_MMX(mmr1, mmr2) // use MMX version
#define V_PMAXUB(mmr1, mmr2) V_PMAXUB2(mmr1, mmr2, SSE_TYPE)
#define V_PMAXUB2(mmr1, mmr2, ssetyp) V_PMAXUB3(mmr1, mmr2, ssetyp)
#define V_PMAXUB3(mmr1, mmr2, ssetyp) V_PMAXUB_##ssetyp(mmr1, mmr2)
// some macros for pminub instruction
// V_PMINUB(mmr1, mmr2, mmr work register) mmr2 may NOT = mmrw
#define V_PMINUB_MMX(mmr1, mmr2, mmrw) \
"pcmpeqb "mmrw", "mmrw"\n\t" \
"psubusb "mmr2", "mmrw"\n\t" \
"paddusb "mmrw", "mmr1"\n\t" \
"psubusb "mmrw", "mmr1"\n\t"
#define V_PMINUB_SSE(mmr1, mmr2, mmrw) "pminub "mmr2", "mmr1"\n\t"
#define V_PMINUB_3DNOW(mmr1, mmr2, mmrw) V_PMINUB_MMX(mmr1, mmr2, mmrw) // use MMX version
#define V_PMINUB(mmr1, mmr2, mmrw) V_PMINUB2(mmr1, mmr2, mmrw, SSE_TYPE)
#define V_PMINUB2(mmr1, mmr2, mmrw, ssetyp) V_PMINUB3(mmr1, mmr2, mmrw, ssetyp)
#define V_PMINUB3(mmr1, mmr2, mmrw, ssetyp) V_PMINUB_##ssetyp(mmr1, mmr2, mmrw)
// some macros for movntq instruction
// V_MOVNTQ(mmr1, mmr2)
#define V_MOVNTQ_MMX(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t"
#define V_MOVNTQ_3DNOW(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t"
#define V_MOVNTQ_SSE(mmr1, mmr2) "movntq "mmr2", "mmr1"\n\t"
#define V_MOVNTQ(mmr1, mmr2) V_MOVNTQ2(mmr1, mmr2, SSE_TYPE)
#define V_MOVNTQ2(mmr1, mmr2, ssetyp) V_MOVNTQ3(mmr1, mmr2, ssetyp)
#define V_MOVNTQ3(mmr1, mmr2, ssetyp) V_MOVNTQ_##ssetyp(mmr1, mmr2)
// end of macros

View file

@ -0,0 +1,723 @@
/* mmx.h
MultiMedia eXtensions GCC interface library for IA32.
To use this library, simply include this header file
and compile with GCC. You MUST have inlining enabled
in order for mmx_ok() to work; this can be done by
simply using -O on the GCC command line.
Compiling with -DMMX_TRACE will cause detailed trace
output to be sent to stderr for each mmx operation.
This adds lots of code, and obviously slows execution to
a crawl, but can be very useful for debugging.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR ANY PARTICULAR PURPOSE.
1997-98 by H. Dietz and R. Fisher
History:
97-98* R.Fisher Early versions
980501 R.Fisher Original Release
980611* H.Dietz Rewrite, correctly implementing inlines, and
R.Fisher including direct register accesses.
980616 R.Fisher Release of 980611 as 980616.
980714 R.Fisher Minor corrections to Makefile, etc.
980715 R.Fisher mmx_ok() now prevents optimizer from using
clobbered values.
mmx_ok() now checks if cpuid instruction is
available before trying to use it.
980726* R.Fisher mm_support() searches for AMD 3DNow, Cyrix
Extended MMX, and standard MMX. It returns a
value which is positive if any of these are
supported, and can be masked with constants to
see which. mmx_ok() is now a call to this
980726* R.Fisher Added i2r support for shift functions
980919 R.Fisher Fixed AMD extended feature recognition bug.
980921 R.Fisher Added definition/check for _MMX_H.
Added "float s[2]" to mmx_t for use with
3DNow and EMMX. So same mmx_t can be used.
981013 R.Fisher Fixed cpuid function 1 bug (looked at wrong reg)
Fixed psllq_i2r error in mmxtest.c
* Unreleased (internal or interim) versions
Notes:
It appears that the latest gas has the pand problem fixed, therefore
I'll undefine BROKEN_PAND by default.
String compares may be quicker than the multiple test/jumps in vendor
test sequence in mmx_ok(), but I'm not concerned with that right now.
Acknowledgments:
Jussi Laako for pointing out the errors ultimately found to be
connected to the failure to notify the optimizer of clobbered values.
Roger Hardiman for reminding us that CPUID isn't everywhere, and that
someone may actually try to use this on a machine without CPUID.
Also for suggesting code for checking this.
Robert Dale for pointing out the AMD recognition bug.
Jimmy Mayfield and Carl Witty for pointing out the Intel recognition
bug.
Carl Witty for pointing out the psllq_i2r test bug.
*/
#ifndef _MMX_H
#define _MMX_H
/*#define MMX_TRACE */
/* Warning: at this writing, the version of GAS packaged
with most Linux distributions does not handle the
parallel AND operation mnemonic correctly. If the
symbol BROKEN_PAND is defined, a slower alternative
coding will be used. If execution of mmxtest results
in an illegal instruction fault, define this symbol.
*/
#undef BROKEN_PAND
/* The type of an value that fits in an MMX register
(note that long long constant values MUST be suffixed
by LL and unsigned long long values by ULL, lest
they be truncated by the compiler)
*/
typedef union {
long long q; /* Quadword (64-bit) value */
unsigned long long uq; /* Unsigned Quadword */
int d[2]; /* 2 Doubleword (32-bit) values */
unsigned int ud[2]; /* 2 Unsigned Doubleword */
short w[4]; /* 4 Word (16-bit) values */
unsigned short uw[4]; /* 4 Unsigned Word */
char b[8]; /* 8 Byte (8-bit) values */
unsigned char ub[8]; /* 8 Unsigned Byte */
float s[2]; /* Single-precision (32-bit) value */
} mmx_t;
/* Function to test if multimedia instructions are supported...
*/
inline extern int
mm_support(void)
{
/* Returns 1 if MMX instructions are supported,
3 if Cyrix MMX and Extended MMX instructions are supported
5 if AMD MMX and 3DNow! instructions are supported
0 if hardware does not support any of these
*/
register int rval = 0;
__asm__ __volatile__ (
/* See if CPUID instruction is supported ... */
/* ... Get copies of EFLAGS into eax and ecx */
"pushf\n\t"
"popl %%eax\n\t"
"movl %%eax, %%ecx\n\t"
/* ... Toggle the ID bit in one copy and store */
/* to the EFLAGS reg */
"xorl $0x200000, %%eax\n\t"
"push %%eax\n\t"
"popf\n\t"
/* ... Get the (hopefully modified) EFLAGS */
"pushf\n\t"
"popl %%eax\n\t"
/* ... Compare and test result */
"xorl %%eax, %%ecx\n\t"
"testl $0x200000, %%ecx\n\t"
"jz NotSupported1\n\t" /* Nothing supported */
/* Get standard CPUID information, and
go to a specific vendor section */
"movl $0, %%eax\n\t"
"cpuid\n\t"
/* Check for Intel */
"cmpl $0x756e6547, %%ebx\n\t"
"jne TryAMD\n\t"
"cmpl $0x49656e69, %%edx\n\t"
"jne TryAMD\n\t"
"cmpl $0x6c65746e, %%ecx\n"
"jne TryAMD\n\t"
"jmp Intel\n\t"
/* Check for AMD */
"\nTryAMD:\n\t"
"cmpl $0x68747541, %%ebx\n\t"
"jne TryCyrix\n\t"
"cmpl $0x69746e65, %%edx\n\t"
"jne TryCyrix\n\t"
"cmpl $0x444d4163, %%ecx\n"
"jne TryCyrix\n\t"
"jmp AMD\n\t"
/* Check for Cyrix */
"\nTryCyrix:\n\t"
"cmpl $0x69727943, %%ebx\n\t"
"jne NotSupported2\n\t"
"cmpl $0x736e4978, %%edx\n\t"
"jne NotSupported3\n\t"
"cmpl $0x64616574, %%ecx\n\t"
"jne NotSupported4\n\t"
/* Drop through to Cyrix... */
/* Cyrix Section */
/* See if extended CPUID is supported */
"movl $0x80000000, %%eax\n\t"
"cpuid\n\t"
"cmpl $0x80000000, %%eax\n\t"
"jl MMXtest\n\t" /* Try standard CPUID instead */
/* Extended CPUID supported, so get extended features */
"movl $0x80000001, %%eax\n\t"
"cpuid\n\t"
"testl $0x00800000, %%eax\n\t" /* Test for MMX */
"jz NotSupported5\n\t" /* MMX not supported */
"testl $0x01000000, %%eax\n\t" /* Test for Ext'd MMX */
"jnz EMMXSupported\n\t"
"movl $1, %0:\n\n\t" /* MMX Supported */
"jmp Return\n\n"
"EMMXSupported:\n\t"
"movl $3, %0:\n\n\t" /* EMMX and MMX Supported */
"jmp Return\n\t"
/* AMD Section */
"AMD:\n\t"
/* See if extended CPUID is supported */
"movl $0x80000000, %%eax\n\t"
"cpuid\n\t"
"cmpl $0x80000000, %%eax\n\t"
"jl MMXtest\n\t" /* Try standard CPUID instead */
/* Extended CPUID supported, so get extended features */
"movl $0x80000001, %%eax\n\t"
"cpuid\n\t"
"testl $0x00800000, %%edx\n\t" /* Test for MMX */
"jz NotSupported6\n\t" /* MMX not supported */
"testl $0x80000000, %%edx\n\t" /* Test for 3DNow! */
"jnz ThreeDNowSupported\n\t"
"movl $1, %0:\n\n\t" /* MMX Supported */
"jmp Return\n\n"
"ThreeDNowSupported:\n\t"
"movl $5, %0:\n\n\t" /* 3DNow! and MMX Supported */
"jmp Return\n\t"
/* Intel Section */
"Intel:\n\t"
/* Check for MMX */
"MMXtest:\n\t"
"movl $1, %%eax\n\t"
"cpuid\n\t"
"testl $0x00800000, %%edx\n\t" /* Test for MMX */
"jz NotSupported7\n\t" /* MMX Not supported */
"movl $1, %0:\n\n\t" /* MMX Supported */
"jmp Return\n\t"
/* Nothing supported */
"\nNotSupported1:\n\t"
"#movl $101, %0:\n\n\t"
"\nNotSupported2:\n\t"
"#movl $102, %0:\n\n\t"
"\nNotSupported3:\n\t"
"#movl $103, %0:\n\n\t"
"\nNotSupported4:\n\t"
"#movl $104, %0:\n\n\t"
"\nNotSupported5:\n\t"
"#movl $105, %0:\n\n\t"
"\nNotSupported6:\n\t"
"#movl $106, %0:\n\n\t"
"\nNotSupported7:\n\t"
"#movl $107, %0:\n\n\t"
"movl $0, %0:\n\n\t"
"Return:\n\t"
: "=a" (rval)
: /* no input */
: "eax", "ebx", "ecx", "edx"
);
/* Return */
return(rval);
}
/* Function to test if mmx instructions are supported...
*/
inline extern int
mmx_ok(void)
{
/* Returns 1 if MMX instructions are supported, 0 otherwise */
return ( mm_support() & 0x1 );
}
/* Helper functions for the instruction macros that follow...
(note that memory-to-register, m2r, instructions are nearly
as efficient as register-to-register, r2r, instructions;
however, memory-to-memory instructions are really simulated
as a convenience, and are only 1/3 as efficient)
*/
#ifdef MMX_TRACE
/* Include the stuff for printing a trace to stderr...
*/
#include <stdio.h>
#define mmx_i2r(op, imm, reg) \
{ \
mmx_t mmx_trace; \
mmx_trace = (imm); \
fprintf(stderr, #op "_i2r(" #imm "=0x%016llx, ", mmx_trace.q); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (imm)); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \
}
#define mmx_m2r(op, mem, reg) \
{ \
mmx_t mmx_trace; \
mmx_trace = (mem); \
fprintf(stderr, #op "_m2r(" #mem "=0x%016llx, ", mmx_trace.q); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (mem)); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \
}
#define mmx_r2m(op, reg, mem) \
{ \
mmx_t mmx_trace; \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #op "_r2m(" #reg "=0x%016llx, ", mmx_trace.q); \
mmx_trace = (mem); \
fprintf(stderr, #mem "=0x%016llx) => ", mmx_trace.q); \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
: "=X" (mem) \
: /* nothing */ ); \
mmx_trace = (mem); \
fprintf(stderr, #mem "=0x%016llx\n", mmx_trace.q); \
}
#define mmx_r2r(op, regs, regd) \
{ \
mmx_t mmx_trace; \
__asm__ __volatile__ ("movq %%" #regs ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #op "_r2r(" #regs "=0x%016llx, ", mmx_trace.q); \
__asm__ __volatile__ ("movq %%" #regd ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #regd "=0x%016llx) => ", mmx_trace.q); \
__asm__ __volatile__ (#op " %" #regs ", %" #regd); \
__asm__ __volatile__ ("movq %%" #regd ", %0" \
: "=X" (mmx_trace) \
: /* nothing */ ); \
fprintf(stderr, #regd "=0x%016llx\n", mmx_trace.q); \
}
#define mmx_m2m(op, mems, memd) \
{ \
mmx_t mmx_trace; \
mmx_trace = (mems); \
fprintf(stderr, #op "_m2m(" #mems "=0x%016llx, ", mmx_trace.q); \
mmx_trace = (memd); \
fprintf(stderr, #memd "=0x%016llx) => ", mmx_trace.q); \
__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
#op " %1, %%mm0\n\t" \
"movq %%mm0, %0" \
: "=X" (memd) \
: "X" (mems)); \
mmx_trace = (memd); \
fprintf(stderr, #memd "=0x%016llx\n", mmx_trace.q); \
}
#else
/* These macros are a lot simpler without the tracing...
*/
#define mmx_i2r(op, imm, reg) \
__asm__ __volatile__ (#op " $" #imm ", %%" #reg \
: /* nothing */ \
: /* nothing */);
#define mmx_m2r(op, mem, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "m" (mem))
#define mmx_r2m(op, reg, mem) \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
: "=m" (mem) \
: /* nothing */ )
#define mmx_r2r(op, regs, regd) \
__asm__ __volatile__ (#op " %" #regs ", %" #regd)
#define mmx_m2m(op, mems, memd) \
__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
#op " %1, %%mm0\n\t" \
"movq %%mm0, %0" \
: "=m" (memd) \
: "m" (mems))
#endif
/* 1x64 MOVe Quadword
(this is both a load and a store...
in fact, it is the only way to store)
*/
#define movq_m2r(var, reg) mmx_m2r(movq, var, reg)
#define movq_r2m(reg, var) mmx_r2m(movq, reg, var)
#define movq_r2r(regs, regd) mmx_r2r(movq, regs, regd)
#define movq(vars, vard) \
__asm__ __volatile__ ("movq %1, %%mm0\n\t" \
"movq %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* 1x32 MOVe Doubleword
(like movq, this is both load and store...
but is most useful for moving things between
mmx registers and ordinary registers)
*/
#define movd_m2r(var, reg) mmx_m2r(movd, var, reg)
#define movd_r2m(reg, var) mmx_r2m(movd, reg, var)
#define movd_r2r(regs, regd) mmx_r2r(movd, regs, regd)
#define movd(vars, vard) \
__asm__ __volatile__ ("movd %1, %%mm0\n\t" \
"movd %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* 2x32, 4x16, and 8x8 Parallel ADDs
*/
#define paddd_m2r(var, reg) mmx_m2r(paddd, var, reg)
#define paddd_r2r(regs, regd) mmx_r2r(paddd, regs, regd)
#define paddd(vars, vard) mmx_m2m(paddd, vars, vard)
#define paddw_m2r(var, reg) mmx_m2r(paddw, var, reg)
#define paddw_r2r(regs, regd) mmx_r2r(paddw, regs, regd)
#define paddw(vars, vard) mmx_m2m(paddw, vars, vard)
#define paddb_m2r(var, reg) mmx_m2r(paddb, var, reg)
#define paddb_r2r(regs, regd) mmx_r2r(paddb, regs, regd)
#define paddb(vars, vard) mmx_m2m(paddb, vars, vard)
/* 4x16 and 8x8 Parallel ADDs using Saturation arithmetic
*/
#define paddsw_m2r(var, reg) mmx_m2r(paddsw, var, reg)
#define paddsw_r2r(regs, regd) mmx_r2r(paddsw, regs, regd)
#define paddsw(vars, vard) mmx_m2m(paddsw, vars, vard)
#define paddsb_m2r(var, reg) mmx_m2r(paddsb, var, reg)
#define paddsb_r2r(regs, regd) mmx_r2r(paddsb, regs, regd)
#define paddsb(vars, vard) mmx_m2m(paddsb, vars, vard)
/* 4x16 and 8x8 Parallel ADDs using Unsigned Saturation arithmetic
*/
#define paddusw_m2r(var, reg) mmx_m2r(paddusw, var, reg)
#define paddusw_r2r(regs, regd) mmx_r2r(paddusw, regs, regd)
#define paddusw(vars, vard) mmx_m2m(paddusw, vars, vard)
#define paddusb_m2r(var, reg) mmx_m2r(paddusb, var, reg)
#define paddusb_r2r(regs, regd) mmx_r2r(paddusb, regs, regd)
#define paddusb(vars, vard) mmx_m2m(paddusb, vars, vard)
/* 2x32, 4x16, and 8x8 Parallel SUBs
*/
#define psubd_m2r(var, reg) mmx_m2r(psubd, var, reg)
#define psubd_r2r(regs, regd) mmx_r2r(psubd, regs, regd)
#define psubd(vars, vard) mmx_m2m(psubd, vars, vard)
#define psubw_m2r(var, reg) mmx_m2r(psubw, var, reg)
#define psubw_r2r(regs, regd) mmx_r2r(psubw, regs, regd)
#define psubw(vars, vard) mmx_m2m(psubw, vars, vard)
#define psubb_m2r(var, reg) mmx_m2r(psubb, var, reg)
#define psubb_r2r(regs, regd) mmx_r2r(psubb, regs, regd)
#define psubb(vars, vard) mmx_m2m(psubb, vars, vard)
/* 4x16 and 8x8 Parallel SUBs using Saturation arithmetic
*/
#define psubsw_m2r(var, reg) mmx_m2r(psubsw, var, reg)
#define psubsw_r2r(regs, regd) mmx_r2r(psubsw, regs, regd)
#define psubsw(vars, vard) mmx_m2m(psubsw, vars, vard)
#define psubsb_m2r(var, reg) mmx_m2r(psubsb, var, reg)
#define psubsb_r2r(regs, regd) mmx_r2r(psubsb, regs, regd)
#define psubsb(vars, vard) mmx_m2m(psubsb, vars, vard)
/* 4x16 and 8x8 Parallel SUBs using Unsigned Saturation arithmetic
*/
#define psubusw_m2r(var, reg) mmx_m2r(psubusw, var, reg)
#define psubusw_r2r(regs, regd) mmx_r2r(psubusw, regs, regd)
#define psubusw(vars, vard) mmx_m2m(psubusw, vars, vard)
#define psubusb_m2r(var, reg) mmx_m2r(psubusb, var, reg)
#define psubusb_r2r(regs, regd) mmx_r2r(psubusb, regs, regd)
#define psubusb(vars, vard) mmx_m2m(psubusb, vars, vard)
/* 4x16 Parallel MULs giving Low 4x16 portions of results
*/
#define pmullw_m2r(var, reg) mmx_m2r(pmullw, var, reg)
#define pmullw_r2r(regs, regd) mmx_r2r(pmullw, regs, regd)
#define pmullw(vars, vard) mmx_m2m(pmullw, vars, vard)
/* 4x16 Parallel MULs giving High 4x16 portions of results
*/
#define pmulhw_m2r(var, reg) mmx_m2r(pmulhw, var, reg)
#define pmulhw_r2r(regs, regd) mmx_r2r(pmulhw, regs, regd)
#define pmulhw(vars, vard) mmx_m2m(pmulhw, vars, vard)
/* 4x16->2x32 Parallel Mul-ADD
(muls like pmullw, then adds adjacent 16-bit fields
in the multiply result to make the final 2x32 result)
*/
#define pmaddwd_m2r(var, reg) mmx_m2r(pmaddwd, var, reg)
#define pmaddwd_r2r(regs, regd) mmx_r2r(pmaddwd, regs, regd)
#define pmaddwd(vars, vard) mmx_m2m(pmaddwd, vars, vard)
/* 1x64 bitwise AND
*/
#ifdef BROKEN_PAND
#define pand_m2r(var, reg) \
{ \
mmx_m2r(pandn, (mmx_t) -1LL, reg); \
mmx_m2r(pandn, var, reg); \
}
#define pand_r2r(regs, regd) \
{ \
mmx_m2r(pandn, (mmx_t) -1LL, regd); \
mmx_r2r(pandn, regs, regd); \
}
#define pand(vars, vard) \
{ \
movq_m2r(vard, mm0); \
mmx_m2r(pandn, (mmx_t) -1LL, mm0); \
mmx_m2r(pandn, vars, mm0); \
movq_r2m(mm0, vard); \
}
#else
#define pand_m2r(var, reg) mmx_m2r(pand, var, reg)
#define pand_r2r(regs, regd) mmx_r2r(pand, regs, regd)
#define pand(vars, vard) mmx_m2m(pand, vars, vard)
#endif
/* 1x64 bitwise AND with Not the destination
*/
#define pandn_m2r(var, reg) mmx_m2r(pandn, var, reg)
#define pandn_r2r(regs, regd) mmx_r2r(pandn, regs, regd)
#define pandn(vars, vard) mmx_m2m(pandn, vars, vard)
/* 1x64 bitwise OR
*/
#define por_m2r(var, reg) mmx_m2r(por, var, reg)
#define por_r2r(regs, regd) mmx_r2r(por, regs, regd)
#define por(vars, vard) mmx_m2m(por, vars, vard)
/* 1x64 bitwise eXclusive OR
*/
#define pxor_m2r(var, reg) mmx_m2r(pxor, var, reg)
#define pxor_r2r(regs, regd) mmx_r2r(pxor, regs, regd)
#define pxor(vars, vard) mmx_m2m(pxor, vars, vard)
/* 2x32, 4x16, and 8x8 Parallel CoMPare for EQuality
(resulting fields are either 0 or -1)
*/
#define pcmpeqd_m2r(var, reg) mmx_m2r(pcmpeqd, var, reg)
#define pcmpeqd_r2r(regs, regd) mmx_r2r(pcmpeqd, regs, regd)
#define pcmpeqd(vars, vard) mmx_m2m(pcmpeqd, vars, vard)
#define pcmpeqw_m2r(var, reg) mmx_m2r(pcmpeqw, var, reg)
#define pcmpeqw_r2r(regs, regd) mmx_r2r(pcmpeqw, regs, regd)
#define pcmpeqw(vars, vard) mmx_m2m(pcmpeqw, vars, vard)
#define pcmpeqb_m2r(var, reg) mmx_m2r(pcmpeqb, var, reg)
#define pcmpeqb_r2r(regs, regd) mmx_r2r(pcmpeqb, regs, regd)
#define pcmpeqb(vars, vard) mmx_m2m(pcmpeqb, vars, vard)
/* 2x32, 4x16, and 8x8 Parallel CoMPare for Greater Than
(resulting fields are either 0 or -1)
*/
#define pcmpgtd_m2r(var, reg) mmx_m2r(pcmpgtd, var, reg)
#define pcmpgtd_r2r(regs, regd) mmx_r2r(pcmpgtd, regs, regd)
#define pcmpgtd(vars, vard) mmx_m2m(pcmpgtd, vars, vard)
#define pcmpgtw_m2r(var, reg) mmx_m2r(pcmpgtw, var, reg)
#define pcmpgtw_r2r(regs, regd) mmx_r2r(pcmpgtw, regs, regd)
#define pcmpgtw(vars, vard) mmx_m2m(pcmpgtw, vars, vard)
#define pcmpgtb_m2r(var, reg) mmx_m2r(pcmpgtb, var, reg)
#define pcmpgtb_r2r(regs, regd) mmx_r2r(pcmpgtb, regs, regd)
#define pcmpgtb(vars, vard) mmx_m2m(pcmpgtb, vars, vard)
/* 1x64, 2x32, and 4x16 Parallel Shift Left Logical
*/
#define psllq_i2r(imm, reg) mmx_i2r(psllq, imm, reg)
#define psllq_m2r(var, reg) mmx_m2r(psllq, var, reg)
#define psllq_r2r(regs, regd) mmx_r2r(psllq, regs, regd)
#define psllq(vars, vard) mmx_m2m(psllq, vars, vard)
#define pslld_i2r(imm, reg) mmx_i2r(pslld, imm, reg)
#define pslld_m2r(var, reg) mmx_m2r(pslld, var, reg)
#define pslld_r2r(regs, regd) mmx_r2r(pslld, regs, regd)
#define pslld(vars, vard) mmx_m2m(pslld, vars, vard)
#define psllw_i2r(imm, reg) mmx_i2r(psllw, imm, reg)
#define psllw_m2r(var, reg) mmx_m2r(psllw, var, reg)
#define psllw_r2r(regs, regd) mmx_r2r(psllw, regs, regd)
#define psllw(vars, vard) mmx_m2m(psllw, vars, vard)
/* 1x64, 2x32, and 4x16 Parallel Shift Right Logical
*/
#define psrlq_i2r(imm, reg) mmx_i2r(psrlq, imm, reg)
#define psrlq_m2r(var, reg) mmx_m2r(psrlq, var, reg)
#define psrlq_r2r(regs, regd) mmx_r2r(psrlq, regs, regd)
#define psrlq(vars, vard) mmx_m2m(psrlq, vars, vard)
#define psrld_i2r(imm, reg) mmx_i2r(psrld, imm, reg)
#define psrld_m2r(var, reg) mmx_m2r(psrld, var, reg)
#define psrld_r2r(regs, regd) mmx_r2r(psrld, regs, regd)
#define psrld(vars, vard) mmx_m2m(psrld, vars, vard)
#define psrlw_i2r(imm, reg) mmx_i2r(psrlw, imm, reg)
#define psrlw_m2r(var, reg) mmx_m2r(psrlw, var, reg)
#define psrlw_r2r(regs, regd) mmx_r2r(psrlw, regs, regd)
#define psrlw(vars, vard) mmx_m2m(psrlw, vars, vard)
/* 2x32 and 4x16 Parallel Shift Right Arithmetic
*/
#define psrad_i2r(imm, reg) mmx_i2r(psrad, imm, reg)
#define psrad_m2r(var, reg) mmx_m2r(psrad, var, reg)
#define psrad_r2r(regs, regd) mmx_r2r(psrad, regs, regd)
#define psrad(vars, vard) mmx_m2m(psrad, vars, vard)
#define psraw_i2r(imm, reg) mmx_i2r(psraw, imm, reg)
#define psraw_m2r(var, reg) mmx_m2r(psraw, var, reg)
#define psraw_r2r(regs, regd) mmx_r2r(psraw, regs, regd)
#define psraw(vars, vard) mmx_m2m(psraw, vars, vard)
/* 2x32->4x16 and 4x16->8x8 PACK and Signed Saturate
(packs source and dest fields into dest in that order)
*/
#define packssdw_m2r(var, reg) mmx_m2r(packssdw, var, reg)
#define packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd)
#define packssdw(vars, vard) mmx_m2m(packssdw, vars, vard)
#define packsswb_m2r(var, reg) mmx_m2r(packsswb, var, reg)
#define packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd)
#define packsswb(vars, vard) mmx_m2m(packsswb, vars, vard)
/* 4x16->8x8 PACK and Unsigned Saturate
(packs source and dest fields into dest in that order)
*/
#define packuswb_m2r(var, reg) mmx_m2r(packuswb, var, reg)
#define packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd)
#define packuswb(vars, vard) mmx_m2m(packuswb, vars, vard)
/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK Low
(interleaves low half of dest with low half of source
as padding in each result field)
*/
#define punpckldq_m2r(var, reg) mmx_m2r(punpckldq, var, reg)
#define punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd)
#define punpckldq(vars, vard) mmx_m2m(punpckldq, vars, vard)
#define punpcklwd_m2r(var, reg) mmx_m2r(punpcklwd, var, reg)
#define punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd)
#define punpcklwd(vars, vard) mmx_m2m(punpcklwd, vars, vard)
#define punpcklbw_m2r(var, reg) mmx_m2r(punpcklbw, var, reg)
#define punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd)
#define punpcklbw(vars, vard) mmx_m2m(punpcklbw, vars, vard)
/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK High
(interleaves high half of dest with high half of source
as padding in each result field)
*/
#define punpckhdq_m2r(var, reg) mmx_m2r(punpckhdq, var, reg)
#define punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd)
#define punpckhdq(vars, vard) mmx_m2m(punpckhdq, vars, vard)
#define punpckhwd_m2r(var, reg) mmx_m2r(punpckhwd, var, reg)
#define punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd)
#define punpckhwd(vars, vard) mmx_m2m(punpckhwd, vars, vard)
#define punpckhbw_m2r(var, reg) mmx_m2r(punpckhbw, var, reg)
#define punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd)
#define punpckhbw(vars, vard) mmx_m2m(punpckhbw, vars, vard)
/* Empty MMx State
(used to clean-up when going from mmx to float use
of the registers that are shared by both; note that
there is no float-to-mmx operation needed, because
only the float tag word info is corruptible)
*/
#ifdef MMX_TRACE
#define emms() \
{ \
fprintf(stderr, "emms()\n"); \
__asm__ __volatile__ ("emms"); \
}
#else
#define emms() __asm__ __volatile__ ("emms")
#endif
#endif

View file

@ -0,0 +1,42 @@
/*
*
* GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#ifndef TVTIME_PLUGINS_H_INCLUDED
#define TVTIME_PLUGINS_H_INCLUDED
deinterlace_method_t* dscaler_tomsmocomp_get_method( void );
deinterlace_method_t* dscaler_greedyh_get_method( void );
deinterlace_method_t* dscaler_greedyl_get_method( void );
deinterlace_method_t* dscaler_vfir_get_method( void );
//void linear_plugin_init( void );
//void scalerbob_plugin_init( void );
//void linearblend_plugin_init( void );
//void weave_plugin_init( void );
//void weavetff_plugin_init( void );
//void weavebff_plugin_init( void );
#endif /* TVTIME_PLUGINS_H_INCLUDED */

View file

@ -0,0 +1,54 @@
/*
*
* GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#ifndef SPEEDTOOLS_H_INCLUDED
#define SPEEDTOOLS_H_INCLUDED
#define PREFETCH_2048(x) \
{ int *pfetcha = (int *) x; \
prefetchnta( pfetcha ); \
prefetchnta( pfetcha + 64 ); \
prefetchnta( pfetcha + 128 ); \
prefetchnta( pfetcha + 192 ); \
pfetcha += 256; \
prefetchnta( pfetcha ); \
prefetchnta( pfetcha + 64 ); \
prefetchnta( pfetcha + 128 ); \
prefetchnta( pfetcha + 192 ); }
#define READ_PREFETCH_2048(x) \
{ int *pfetcha = (int *) x; int pfetchtmp; \
pfetchtmp = pfetcha[ 0 ] + pfetcha[ 16 ] + pfetcha[ 32 ] + pfetcha[ 48 ] + \
pfetcha[ 64 ] + pfetcha[ 80 ] + pfetcha[ 96 ] + pfetcha[ 112 ] + \
pfetcha[ 128 ] + pfetcha[ 144 ] + pfetcha[ 160 ] + pfetcha[ 176 ] + \
pfetcha[ 192 ] + pfetcha[ 208 ] + pfetcha[ 224 ] + pfetcha[ 240 ]; \
pfetcha += 256; \
pfetchtmp = pfetcha[ 0 ] + pfetcha[ 16 ] + pfetcha[ 32 ] + pfetcha[ 48 ] + \
pfetcha[ 64 ] + pfetcha[ 80 ] + pfetcha[ 96 ] + pfetcha[ 112 ] + \
pfetcha[ 128 ] + pfetcha[ 144 ] + pfetcha[ 160 ] + pfetcha[ 176 ] + \
pfetcha[ 192 ] + pfetcha[ 208 ] + pfetcha[ 224 ] + pfetcha[ 240 ]; }
#endif /* SPEEDTOOLS_H_INCLUDED */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,308 @@
/*
*
* GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#ifndef SPEEDY_H_INCLUDED
#define SPEEDY_H_INCLUDED
#if defined (__SVR4) && defined (__sun)
# include <sys/int_types.h>
#else
# include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* Speedy is a collection of optimized functions plus their C fallbacks.
* This includes a simple system to select which functions to use
* at runtime.
*
* The optimizations are done with the help of the mmx.h system, from
* libmpeg2 by Michel Lespinasse and Aaron Holtzman.
*
* The library is a collection of function pointers which must be first
* initialized by setup_speedy_calls() to point at the fastest available
* implementation of each function.
*/
/**
* Struct for pulldown detection metrics.
*/
typedef struct pulldown_metrics_s {
/* difference: total, even lines, odd lines */
int d, e, o;
/* noise: temporal, spacial (current), spacial (past) */
int t, s, p;
} pulldown_metrics_t;
/**
* Interpolates a packed 4:2:2 scanline using linear interpolation.
*/
extern void (*interpolate_packed422_scanline)( uint8_t *output, uint8_t *top,
uint8_t *bot, int width );
/**
* Blits a colour to a packed 4:2:2 scanline.
*/
extern void (*blit_colour_packed422_scanline)( uint8_t *output,
int width, int y, int cb, int cr );
/**
* Blits a colour to a packed 4:4:4:4 scanline. I use luma/cb/cr instead of
* RGB but this will of course work for either.
*/
extern void (*blit_colour_packed4444_scanline)( uint8_t *output,
int width, int alpha, int luma,
int cb, int cr );
/**
* Blit from and to packed 4:2:2 scanline.
*/
extern void (*blit_packed422_scanline)( uint8_t *dest, const uint8_t *src, int width );
/**
* Composites a premultiplied 4:4:4:4 pixel onto a packed 4:2:2 scanline.
*/
extern void (*composite_colour4444_alpha_to_packed422_scanline)( uint8_t *output, uint8_t *input,
int af, int y, int cb, int cr,
int width, int alpha );
/**
* Composites a packed 4:4:4:4 scanline onto a packed 4:2:2 scanline.
* Chroma is downsampled by dropping samples (nearest neighbour).
*/
extern void (*composite_packed4444_to_packed422_scanline)( uint8_t *output,
uint8_t *input,
uint8_t *foreground,
int width );
/**
* Composites a packed 4:4:4:4 scanline onto a packed 4:2:2 scanline.
* Chroma is downsampled by dropping samples (nearest neighbour). The
* alpha value provided is in the range 0-256 and is first applied to
* the input (for fadeouts).
*/
extern void (*composite_packed4444_alpha_to_packed422_scanline)( uint8_t *output,
uint8_t *input,
uint8_t *foreground,
int width, int alpha );
/**
* Takes an alphamask and the given colour (in Y'CbCr) and composites it
* onto a packed 4:4:4:4 scanline.
*/
extern void (*composite_alphamask_to_packed4444_scanline)( uint8_t *output,
uint8_t *input,
uint8_t *mask, int width,
int textluma, int textcb,
int textcr );
/**
* Takes an alphamask and the given colour (in Y'CbCr) and composites it
* onto a packed 4:4:4:4 scanline. The alpha value provided is in the
* range 0-256 and is first applied to the input (for fadeouts).
*/
extern void (*composite_alphamask_alpha_to_packed4444_scanline)( uint8_t *output,
uint8_t *input,
uint8_t *mask, int width,
int textluma, int textcb,
int textcr, int alpha );
/**
* Premultiplies the colour by the alpha channel in a packed 4:4:4:4
* scanline.
*/
extern void (*premultiply_packed4444_scanline)( uint8_t *output, uint8_t *input, int width );
/**
* Blend between two packed 4:2:2 scanline. Pos is the fade value in
* the range 0-256. A value of 0 gives 100% src1, and a value of 256
* gives 100% src2. Anything in between gives the appropriate faded
* version.
*/
extern void (*blend_packed422_scanline)( uint8_t *output, uint8_t *src1,
uint8_t *src2, int width, int pos );
/**
* Calculates the 'difference factor' for two scanlines. This is a
* metric where higher values indicate that the two scanlines are more
* different.
*/
extern unsigned int (*diff_factor_packed422_scanline)( uint8_t *cur, uint8_t *old, int width );
/**
* Calculates the 'comb factor' for a set of three scanlines. This is a
* metric where higher values indicate a more likely chance that the two
* fields are at separate points in time.
*/
extern unsigned int (*comb_factor_packed422_scanline)( uint8_t *top, uint8_t *mid,
uint8_t *bot, int width );
/**
* Vertical [1 2 1] chroma filter.
*/
extern void (*vfilter_chroma_121_packed422_scanline)( uint8_t *output, int width,
uint8_t *m, uint8_t *t, uint8_t *b );
/**
* Vertical [3 3 2] chroma filter.
*/
extern void (*vfilter_chroma_332_packed422_scanline)( uint8_t *output, int width,
uint8_t *m, uint8_t *t, uint8_t *b );
/**
* Sets the chroma of the scanline to neutral (128) in-place.
*/
extern void (*kill_chroma_packed422_inplace_scanline)( uint8_t *data, int width );
/**
* Mirrors the scanline in-place.
*/
extern void (*mirror_packed422_inplace_scanline)( uint8_t *data, int width );
/**
* Inverts the colours on a scanline in-place.
*/
extern void (*invert_colour_packed422_inplace_scanline)( uint8_t *data, int width );
/**
* Fast memcpy function, used by all of the blit functions. Won't blit
* anything if dest == src.
*/
extern void (*speedy_memcpy)( void *output, const void *input, size_t size );
/**
* Calculates the block difference metrics for dalias' pulldown
* detection algorithm.
*/
extern void (*diff_packed422_block8x8)( pulldown_metrics_t *m, uint8_t *old,
uint8_t *new, int os, int ns );
/**
* Takes an alpha mask and subpixelly blits it using linear
* interpolation.
*/
extern void (*a8_subpix_blit_scanline)( uint8_t *output, uint8_t *input,
int lasta, int startpos, int width );
/**
* 1/4 vertical subpixel blit for packed 4:2:2 scanlines using linear
* interpolation.
*/
extern void (*quarter_blit_vertical_packed422_scanline)( uint8_t *output, uint8_t *one,
uint8_t *three, int width );
/**
* Vertical subpixel blit for packed 4:2:2 scanlines using linear
* interpolation.
*/
extern void (*subpix_blit_vertical_packed422_scanline)( uint8_t *output, uint8_t *top,
uint8_t *bot, int subpixpos, int width );
/**
* Simple function to convert a 4:4:4 scanline to a 4:4:4:4 scanline by
* adding an alpha channel. Result is non-premultiplied.
*/
extern void (*packed444_to_nonpremultiplied_packed4444_scanline)( uint8_t *output,
uint8_t *input,
int width, int alpha );
/**
* I think this function needs to be rethought and renamed, but here
* it is for now. This function horizontally resamples a scanline
* using linear interpolation to compensate for a change in pixel
* aspect ratio.
*/
extern void (*aspect_adjust_packed4444_scanline)( uint8_t *output,
uint8_t *input,
int width,
double pixel_aspect );
/**
* Convert a packed 4:4:4 surface to a packed 4:2:2 surface using
* nearest neighbour chroma downsampling.
*/
extern void (*packed444_to_packed422_scanline)( uint8_t *output,
uint8_t *input,
int width );
/**
* Converts packed 4:2:2 to packed 4:4:4 scanlines using nearest
* neighbour chroma upsampling.
*/
extern void (*packed422_to_packed444_scanline)( uint8_t *output,
uint8_t *input,
int width );
/**
* This filter actually does not meet the spec so calling it rec601
* is a bit of a lie. I got the filter from Poynton's site. This
* converts a scanline from packed 4:2:2 to packed 4:4:4. But this
* function should point at some high quality to-the-spec resampler.
*/
extern void (*packed422_to_packed444_rec601_scanline)( uint8_t *dest,
uint8_t *src,
int width );
/**
* Conversions between Y'CbCr and R'G'B'. We use Rec.601 numbers
* since our source is broadcast video, but I think there is an
* argument to be made for switching to Rec.709.
*/
extern void (*packed444_to_rgb24_rec601_scanline)( uint8_t *output,
uint8_t *input,
int width );
extern void (*rgb24_to_packed444_rec601_scanline)( uint8_t *output,
uint8_t *input,
int width );
extern void (*rgba32_to_packed4444_rec601_scanline)( uint8_t *output,
uint8_t *input,
int width );
/**
* Convert from 4:2:2 with UYVY ordering to 4:2:2 with YUYV ordering.
*/
extern void (*convert_uyvy_to_yuyv_scanline)( uint8_t *uyvy_buf,
uint8_t *yuyv_buf, int width );
/**
* Sets up the function pointers to point at the fastest function
* available. Requires accelleration settings (see mm_accel.h).
*/
void setup_speedy_calls( uint32_t accel, int verbose );
/**
* Returns a bitfield of what accellerations were used when speedy was
* initialized. See mm_accel.h.
*/
uint32_t speedy_get_accel( void );
#ifdef __cplusplus
};
#endif
#endif /* SPEEDY_H_INCLUDED */

View file

@ -0,0 +1,992 @@
/* sse.h
Streaming SIMD Extenstions (a.k.a. Katmai New Instructions)
GCC interface library for IA32.
To use this library, simply include this header file
and compile with GCC. You MUST have inlining enabled
in order for sse_ok() to work; this can be done by
simply using -O on the GCC command line.
Compiling with -DSSE_TRACE will cause detailed trace
output to be sent to stderr for each sse operation.
This adds lots of code, and obviously slows execution to
a crawl, but can be very useful for debugging.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR ANY PARTICULAR PURPOSE.
1999 by R. Fisher
Based on libmmx by H. Dietz and R. Fisher
Notes:
This is still extremely alpha.
Because this library depends on an assembler which understands the
SSE opcodes, you probably won't be able to use this yet.
For now, do not use TRACE versions. These both make use
of the MMX registers, not the SSE registers. This will be resolved
at a later date.
ToDo:
Rewrite TRACE macros
Major Debugging Work
*/
#ifndef _SSE_H
#define _SSE_H
/* The type of an value that fits in an SSE register
(note that long long constant values MUST be suffixed
by LL and unsigned long long values by ULL, lest
they be truncated by the compiler)
*/
typedef union {
float sf[4]; /* Single-precision (32-bit) value */
} __attribute__ ((aligned (16))) sse_t; /* On a 16 byte (128-bit) boundary */
#if 0
/* Function to test if multimedia instructions are supported...
*/
inline extern int
mm_support(void)
{
/* Returns 1 if MMX instructions are supported,
3 if Cyrix MMX and Extended MMX instructions are supported
5 if AMD MMX and 3DNow! instructions are supported
9 if MMX and SSE instructions are supported
0 if hardware does not support any of these
*/
register int rval = 0;
__asm__ __volatile__ (
/* See if CPUID instruction is supported ... */
/* ... Get copies of EFLAGS into eax and ecx */
"pushf\n\t"
"popl %%eax\n\t"
"movl %%eax, %%ecx\n\t"
/* ... Toggle the ID bit in one copy and store */
/* to the EFLAGS reg */
"xorl $0x200000, %%eax\n\t"
"push %%eax\n\t"
"popf\n\t"
/* ... Get the (hopefully modified) EFLAGS */
"pushf\n\t"
"popl %%eax\n\t"
/* ... Compare and test result */
"xorl %%eax, %%ecx\n\t"
"testl $0x200000, %%ecx\n\t"
"jz NotSupported1\n\t" /* CPUID not supported */
/* Get standard CPUID information, and
go to a specific vendor section */
"movl $0, %%eax\n\t"
"cpuid\n\t"
/* Check for Intel */
"cmpl $0x756e6547, %%ebx\n\t"
"jne TryAMD\n\t"
"cmpl $0x49656e69, %%edx\n\t"
"jne TryAMD\n\t"
"cmpl $0x6c65746e, %%ecx\n"
"jne TryAMD\n\t"
"jmp Intel\n\t"
/* Check for AMD */
"\nTryAMD:\n\t"
"cmpl $0x68747541, %%ebx\n\t"
"jne TryCyrix\n\t"
"cmpl $0x69746e65, %%edx\n\t"
"jne TryCyrix\n\t"
"cmpl $0x444d4163, %%ecx\n"
"jne TryCyrix\n\t"
"jmp AMD\n\t"
/* Check for Cyrix */
"\nTryCyrix:\n\t"
"cmpl $0x69727943, %%ebx\n\t"
"jne NotSupported2\n\t"
"cmpl $0x736e4978, %%edx\n\t"
"jne NotSupported3\n\t"
"cmpl $0x64616574, %%ecx\n\t"
"jne NotSupported4\n\t"
/* Drop through to Cyrix... */
/* Cyrix Section */
/* See if extended CPUID level 80000001 is supported */
/* The value of CPUID/80000001 for the 6x86MX is undefined
according to the Cyrix CPU Detection Guide (Preliminary
Rev. 1.01 table 1), so we'll check the value of eax for
CPUID/0 to see if standard CPUID level 2 is supported.
According to the table, the only CPU which supports level
2 is also the only one which supports extended CPUID levels.
*/
"cmpl $0x2, %%eax\n\t"
"jne MMXtest\n\t" /* Use standard CPUID instead */
/* Extended CPUID supported (in theory), so get extended
features */
"movl $0x80000001, %%eax\n\t"
"cpuid\n\t"
"testl $0x00800000, %%eax\n\t" /* Test for MMX */
"jz NotSupported5\n\t" /* MMX not supported */
"testl $0x01000000, %%eax\n\t" /* Test for Ext'd MMX */
"jnz EMMXSupported\n\t"
"movl $1, %0:\n\n\t" /* MMX Supported */
"jmp Return\n\n"
"EMMXSupported:\n\t"
"movl $3, %0:\n\n\t" /* EMMX and MMX Supported */
"jmp Return\n\t"
/* AMD Section */
"AMD:\n\t"
/* See if extended CPUID is supported */
"movl $0x80000000, %%eax\n\t"
"cpuid\n\t"
"cmpl $0x80000000, %%eax\n\t"
"jl MMXtest\n\t" /* Use standard CPUID instead */
/* Extended CPUID supported, so get extended features */
"movl $0x80000001, %%eax\n\t"
"cpuid\n\t"
"testl $0x00800000, %%edx\n\t" /* Test for MMX */
"jz NotSupported6\n\t" /* MMX not supported */
"testl $0x80000000, %%edx\n\t" /* Test for 3DNow! */
"jnz ThreeDNowSupported\n\t"
"movl $1, %0:\n\n\t" /* MMX Supported */
"jmp Return\n\n"
"ThreeDNowSupported:\n\t"
"movl $5, %0:\n\n\t" /* 3DNow! and MMX Supported */
"jmp Return\n\t"
/* Intel Section */
"Intel:\n\t"
/* Check for SSE */
"SSEtest:\n\t"
"movl $1, %%eax\n\t"
"cpuid\n\t"
"testl $0x02000000, %%edx\n\t" /* Test for SSE */
"jz MMXtest\n\t" /* SSE Not supported */
"movl $9, %0:\n\n\t" /* SSE Supported */
"jmp Return\n\t"
/* Check for MMX */
"MMXtest:\n\t"
"movl $1, %%eax\n\t"
"cpuid\n\t"
"testl $0x00800000, %%edx\n\t" /* Test for MMX */
"jz NotSupported7\n\t" /* MMX Not supported */
"movl $1, %0:\n\n\t" /* MMX Supported */
"jmp Return\n\t"
/* Nothing supported */
"\nNotSupported1:\n\t"
"#movl $101, %0:\n\n\t"
"\nNotSupported2:\n\t"
"#movl $102, %0:\n\n\t"
"\nNotSupported3:\n\t"
"#movl $103, %0:\n\n\t"
"\nNotSupported4:\n\t"
"#movl $104, %0:\n\n\t"
"\nNotSupported5:\n\t"
"#movl $105, %0:\n\n\t"
"\nNotSupported6:\n\t"
"#movl $106, %0:\n\n\t"
"\nNotSupported7:\n\t"
"#movl $107, %0:\n\n\t"
"movl $0, %0:\n\n\t"
"Return:\n\t"
: "=a" (rval)
: /* no input */
: "eax", "ebx", "ecx", "edx"
);
/* Return */
return(rval);
}
/* Function to test if sse instructions are supported...
*/
inline extern int
sse_ok(void)
{
/* Returns 1 if SSE instructions are supported, 0 otherwise */
return ( (mm_support() & 0x8) >> 3 );
}
#endif
/* Helper functions for the instruction macros that follow...
(note that memory-to-register, m2r, instructions are nearly
as efficient as register-to-register, r2r, instructions;
however, memory-to-memory instructions are really simulated
as a convenience, and are only 1/3 as efficient)
*/
#ifdef SSE_TRACE
/* Include the stuff for printing a trace to stderr...
*/
#include <stdio.h>
#define sse_i2r(op, imm, reg) \
{ \
sse_t sse_trace; \
sse_trace.uq = (imm); \
fprintf(stderr, #op "_i2r(" #imm "=0x%08x%08x, ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x) => ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (imm)); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x\n", \
sse_trace.d[1], sse_trace.d[0]); \
}
#define sse_m2r(op, mem, reg) \
{ \
sse_t sse_trace; \
sse_trace = (mem); \
fprintf(stderr, #op "_m2r(" #mem "=0x%08x%08x, ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x) => ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (mem)); \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #reg "=0x%08x%08x\n", \
sse_trace.d[1], sse_trace.d[0]); \
}
#define sse_r2m(op, reg, mem) \
{ \
sse_t sse_trace; \
__asm__ __volatile__ ("movq %%" #reg ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #op "_r2m(" #reg "=0x%08x%08x, ", \
sse_trace.d[1], sse_trace.d[0]); \
sse_trace = (mem); \
fprintf(stderr, #mem "=0x%08x%08x) => ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
: "=X" (mem) \
: /* nothing */ ); \
sse_trace = (mem); \
fprintf(stderr, #mem "=0x%08x%08x\n", \
sse_trace.d[1], sse_trace.d[0]); \
}
#define sse_r2r(op, regs, regd) \
{ \
sse_t sse_trace; \
__asm__ __volatile__ ("movq %%" #regs ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #op "_r2r(" #regs "=0x%08x%08x, ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ ("movq %%" #regd ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #regd "=0x%08x%08x) => ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ (#op " %" #regs ", %" #regd); \
__asm__ __volatile__ ("movq %%" #regd ", %0" \
: "=X" (sse_trace) \
: /* nothing */ ); \
fprintf(stderr, #regd "=0x%08x%08x\n", \
sse_trace.d[1], sse_trace.d[0]); \
}
#define sse_m2m(op, mems, memd) \
{ \
sse_t sse_trace; \
sse_trace = (mems); \
fprintf(stderr, #op "_m2m(" #mems "=0x%08x%08x, ", \
sse_trace.d[1], sse_trace.d[0]); \
sse_trace = (memd); \
fprintf(stderr, #memd "=0x%08x%08x) => ", \
sse_trace.d[1], sse_trace.d[0]); \
__asm__ __volatile__ ("movq %0, %%mm0\n\t" \
#op " %1, %%mm0\n\t" \
"movq %%mm0, %0" \
: "=X" (memd) \
: "X" (mems)); \
sse_trace = (memd); \
fprintf(stderr, #memd "=0x%08x%08x\n", \
sse_trace.d[1], sse_trace.d[0]); \
}
#else
/* These macros are a lot simpler without the tracing...
*/
#define sse_i2r(op, imm, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (imm) )
#define sse_m2r(op, mem, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (mem))
#define sse_r2m(op, reg, mem) \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
: "=X" (mem) \
: /* nothing */ )
#define sse_r2r(op, regs, regd) \
__asm__ __volatile__ (#op " %" #regs ", %" #regd)
#define sse_r2ri(op, regs, regd, imm) \
__asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
: /* nothing */ \
: "X" (imm) )
/* Load data from mems to xmmreg, operate on xmmreg, and store data to memd */
#define sse_m2m(op, mems, memd, xmmreg) \
__asm__ __volatile__ ("movups %0, %%xmm0\n\t" \
#op " %1, %%xmm0\n\t" \
"movups %%mm0, %0" \
: "=X" (memd) \
: "X" (mems))
#define sse_m2ri(op, mem, reg, subop) \
__asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \
: /* nothing */ \
: "X" (mem))
#define sse_m2mi(op, mems, memd, xmmreg, subop) \
__asm__ __volatile__ ("movups %0, %%xmm0\n\t" \
#op " %1, %%xmm0, " #subop "\n\t" \
"movups %%mm0, %0" \
: "=X" (memd) \
: "X" (mems))
#endif
/* 1x128 MOVe Aligned four Packed Single-fp
*/
#define movaps_m2r(var, reg) sse_m2r(movaps, var, reg)
#define movaps_r2m(reg, var) sse_r2m(movaps, reg, var)
#define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd)
#define movaps(vars, vard) \
__asm__ __volatile__ ("movaps %1, %%mm0\n\t" \
"movaps %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* 1x128 MOVe aligned Non-Temporal four Packed Single-fp
*/
#define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var)
/* 1x64 MOVe Non-Temporal Quadword
*/
#define movntq_r2m(mmreg, var) sse_r2m(movntq, mmreg, var)
/* 1x128 MOVe Unaligned four Packed Single-fp
*/
#define movups_m2r(var, reg) sse_m2r(movups, var, reg)
#define movups_r2m(reg, var) sse_r2m(movups, reg, var)
#define movups_r2r(regs, regd) sse_r2r(movups, regs, regd)
#define movups(vars, vard) \
__asm__ __volatile__ ("movups %1, %%mm0\n\t" \
"movups %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* MOVe High to Low Packed Single-fp
high half of 4x32f (x) -> low half of 4x32f (y)
*/
#define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd)
/* MOVe Low to High Packed Single-fp
low half of 4x32f (x) -> high half of 4x32f (y)
*/
#define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd)
/* MOVe High Packed Single-fp
2x32f -> high half of 4x32f
*/
#define movhps_m2r(var, reg) sse_m2r(movhps, var, reg)
#define movhps_r2m(reg, var) sse_r2m(movhps, reg, var)
#define movhps(vars, vard) \
__asm__ __volatile__ ("movhps %1, %%mm0\n\t" \
"movhps %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* MOVe Low Packed Single-fp
2x32f -> low half of 4x32f
*/
#define movlps_m2r(var, reg) sse_m2r(movlps, var, reg)
#define movlps_r2m(reg, var) sse_r2m(movlps, reg, var)
#define movlps(vars, vard) \
__asm__ __volatile__ ("movlps %1, %%mm0\n\t" \
"movlps %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* MOVe Scalar Single-fp
lowest field of 4x32f (x) -> lowest field of 4x32f (y)
*/
#define movss_m2r(var, reg) sse_m2r(movss, var, reg)
#define movss_r2m(reg, var) sse_r2m(movss, reg, var)
#define movss_r2r(regs, regd) sse_r2r(movss, regs, regd)
#define movss(vars, vard) \
__asm__ __volatile__ ("movss %1, %%mm0\n\t" \
"movss %%mm0, %0" \
: "=X" (vard) \
: "X" (vars))
/* 4x16 Packed SHUFfle Word
*/
#define pshufw_m2r(var, reg, index) sse_m2ri(pshufw, var, reg, index)
#define pshufw_r2r(regs, regd, index) sse_r2ri(pshufw, regs, regd, index)
/* 1x128 SHUFfle Packed Single-fp
*/
#define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index)
#define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index)
/* ConVerT Packed signed Int32 to(2) Packed Single-fp
*/
#define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg)
#define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg)
/* ConVerT Packed Single-fp to(2) Packed signed Int32
*/
#define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg)
#define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg)
/* ConVerT with Truncate Packed Single-fp to(2) Packed Int32
*/
#define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg)
#define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg)
/* ConVerT Signed Int32 to(2) Single-fp (Scalar)
*/
#define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg)
#define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg)
/* ConVerT Scalar Single-fp to(2) Signed Int32
*/
#define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
#define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
/* ConVerT with Truncate Scalar Single-fp to(2) Signed Int32
*/
#define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
#define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
/* Parallel EXTRact Word from 4x16
*/
#define pextrw_r2r(mmreg, reg, field) sse_r2ri(pextrw, mmreg, reg, field)
/* Parallel INSeRt Word from 4x16
*/
#define pinsrw_r2r(reg, mmreg, field) sse_r2ri(pinsrw, reg, mmreg, field)
/* MOVe MaSK from Packed Single-fp
*/
#ifdef SSE_TRACE
#define movmskps(xmmreg, reg) \
{ \
fprintf(stderr, "movmskps()\n"); \
__asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) \
}
#else
#define movmskps(xmmreg, reg) \
__asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg)
#endif
/* Parallel MOVe MaSK from mmx reg to 32-bit reg
*/
#ifdef SSE_TRACE
#define pmovmskb(mmreg, reg) \
{ \
fprintf(stderr, "movmskps()\n"); \
__asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) \
}
#else
#define pmovmskb(mmreg, reg) \
__asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg)
#endif
/* MASKed MOVe from 8x8 to memory pointed to by (e)di register
*/
#define maskmovq(mmregs, fieldreg) sse_r2ri(maskmovq, mmregs, fieldreg)
/* 4x32f Parallel ADDs
*/
#define addps_m2r(var, reg) sse_m2r(addps, var, reg)
#define addps_r2r(regs, regd) sse_r2r(addps, regs, regd)
#define addps(vars, vard, xmmreg) sse_m2m(addps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel ADDs
*/
#define addss_m2r(var, reg) sse_m2r(addss, var, reg)
#define addss_r2r(regs, regd) sse_r2r(addss, regs, regd)
#define addss(vars, vard, xmmreg) sse_m2m(addss, vars, vard, xmmreg)
/* 4x32f Parallel SUBs
*/
#define subps_m2r(var, reg) sse_m2r(subps, var, reg)
#define subps_r2r(regs, regd) sse_r2r(subps, regs, regd)
#define subps(vars, vard, xmmreg) sse_m2m(subps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel SUBs
*/
#define subss_m2r(var, reg) sse_m2r(subss, var, reg)
#define subss_r2r(regs, regd) sse_r2r(subss, regs, regd)
#define subss(vars, vard, xmmreg) sse_m2m(subss, vars, vard, xmmreg)
/* 8x8u -> 4x16u Packed Sum of Absolute Differences
*/
#define psadbw_m2r(var, reg) sse_m2r(psadbw, var, reg)
#define psadbw_r2r(regs, regd) sse_r2r(psadbw, regs, regd)
#define psadbw(vars, vard, mmreg) sse_m2m(psadbw, vars, vard, mmreg)
/* 4x16u Parallel MUL High Unsigned
*/
#define pmulhuw_m2r(var, reg) sse_m2r(pmulhuw, var, reg)
#define pmulhuw_r2r(regs, regd) sse_r2r(pmulhuw, regs, regd)
#define pmulhuw(vars, vard, mmreg) sse_m2m(pmulhuw, vars, vard, mmreg)
/* 4x32f Parallel MULs
*/
#define mulps_m2r(var, reg) sse_m2r(mulps, var, reg)
#define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd)
#define mulps(vars, vard, xmmreg) sse_m2m(mulps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel MULs
*/
#define mulss_m2r(var, reg) sse_m2r(mulss, var, reg)
#define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd)
#define mulss(vars, vard, xmmreg) sse_m2m(mulss, vars, vard, xmmreg)
/* 4x32f Parallel DIVs
*/
#define divps_m2r(var, reg) sse_m2r(divps, var, reg)
#define divps_r2r(regs, regd) sse_r2r(divps, regs, regd)
#define divps(vars, vard, xmmreg) sse_m2m(divps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel DIVs
*/
#define divss_m2r(var, reg) sse_m2r(divss, var, reg)
#define divss_r2r(regs, regd) sse_r2r(divss, regs, regd)
#define divss(vars, vard, xmmreg) sse_m2m(divss, vars, vard, xmmreg)
/* 4x32f Parallel Reciprocals
*/
#define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg)
#define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd)
#define rcpps(vars, vard, xmmreg) sse_m2m(rcpps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel Reciprocals
*/
#define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg)
#define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd)
#define rcpss(vars, vard, xmmreg) sse_m2m(rcpss, vars, vard, xmmreg)
/* 4x32f Parallel Square Root of Reciprocals
*/
#define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg)
#define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd)
#define rsqrtps(vars, vard, xmmreg) sse_m2m(rsqrtps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel Square Root of Reciprocals
*/
#define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg)
#define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd)
#define rsqrtss(vars, vard, xmmreg) sse_m2m(rsqrtss, vars, vard, xmmreg)
/* 4x32f Parallel Square Roots
*/
#define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg)
#define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd)
#define sqrtps(vars, vard, xmmreg) sse_m2m(sqrtps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel Square Roots
*/
#define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg)
#define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd)
#define sqrtss(vars, vard, xmmreg) sse_m2m(sqrtss, vars, vard, xmmreg)
/* 8x8u and 4x16u Parallel AVeraGe
*/
#define pavgb_m2r(var, reg) sse_m2r(pavgb, var, reg)
#define pavgb_r2r(regs, regd) sse_r2r(pavgb, regs, regd)
#define pavgb(vars, vard, mmreg) sse_m2m(pavgb, vars, vard, mmreg)
#define pavgw_m2r(var, reg) sse_m2r(pavgw, var, reg)
#define pavgw_r2r(regs, regd) sse_r2r(pavgw, regs, regd)
#define pavgw(vars, vard, mmreg) sse_m2m(pavgw, vars, vard, mmreg)
/* 1x128 bitwise AND
*/
#define andps_m2r(var, reg) sse_m2r(andps, var, reg)
#define andps_r2r(regs, regd) sse_r2r(andps, regs, regd)
#define andps(vars, vard, xmmreg) sse_m2m(andps, vars, vard, xmmreg)
/* 1x128 bitwise AND with Not the destination
*/
#define andnps_m2r(var, reg) sse_m2r(andnps, var, reg)
#define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd)
#define andnps(vars, vard, xmmreg) sse_m2m(andnps, vars, vard, xmmreg)
/* 1x128 bitwise OR
*/
#define orps_m2r(var, reg) sse_m2r(orps, var, reg)
#define orps_r2r(regs, regd) sse_r2r(orps, regs, regd)
#define orps(vars, vard, xmmreg) sse_m2m(orps, vars, vard, xmmreg)
/* 1x128 bitwise eXclusive OR
*/
#define xorps_m2r(var, reg) sse_m2r(xorps, var, reg)
#define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd)
#define xorps(vars, vard, xmmreg) sse_m2m(xorps, vars, vard, xmmreg)
/* 8x8u, 4x16, and 4x32f Parallel Maximum
*/
#define pmaxub_m2r(var, reg) sse_m2r(pmaxub, var, reg)
#define pmaxub_r2r(regs, regd) sse_r2r(pmaxub, regs, regd)
#define pmaxub(vars, vard, mmreg) sse_m2m(pmaxub, vars, vard, mmreg)
#define pmaxsw_m2r(var, reg) sse_m2r(pmaxsw, var, reg)
#define pmaxsw_r2r(regs, regd) sse_r2r(pmaxsw, regs, regd)
#define pmaxsw(vars, vard, mmreg) sse_m2m(pmaxsw, vars, vard, mmreg)
#define maxps_m2r(var, reg) sse_m2r(maxps, var, reg)
#define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd)
#define maxps(vars, vard, xmmreg) sse_m2m(maxps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel Maximum
*/
#define maxss_m2r(var, reg) sse_m2r(maxss, var, reg)
#define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd)
#define maxss(vars, vard, xmmreg) sse_m2m(maxss, vars, vard, xmmreg)
/* 8x8u, 4x16, and 4x32f Parallel Minimum
*/
#define pminub_m2r(var, reg) sse_m2r(pminub, var, reg)
#define pminub_r2r(regs, regd) sse_r2r(pminub, regs, regd)
#define pminub(vars, vard, mmreg) sse_m2m(pminub, vars, vard, mmreg)
#define pminsw_m2r(var, reg) sse_m2r(pminsw, var, reg)
#define pminsw_r2r(regs, regd) sse_r2r(pminsw, regs, regd)
#define pminsw(vars, vard, mmreg) sse_m2m(pminsw, vars, vard, mmreg)
#define minps_m2r(var, reg) sse_m2r(minps, var, reg)
#define minps_r2r(regs, regd) sse_r2r(minps, regs, regd)
#define minps(vars, vard, xmmreg) sse_m2m(minps, vars, vard, xmmreg)
/* Lowest Field of 4x32f Parallel Minimum
*/
#define minss_m2r(var, reg) sse_m2r(minss, var, reg)
#define minss_r2r(regs, regd) sse_r2r(minss, regs, regd)
#define minss(vars, vard, xmmreg) sse_m2m(minss, vars, vard, xmmreg)
/* 4x32f Parallel CoMPares
(resulting fields are either 0 or -1)
*/
#define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op)
#define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op)
#define cmpps(vars, vard, op, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, op)
#define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0)
#define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0)
#define cmpeqps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 0)
#define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1)
#define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1)
#define cmpltps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 1)
#define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2)
#define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2)
#define cmpleps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 2)
#define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3)
#define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3)
#define cmpunordps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 3)
#define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4)
#define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4)
#define cmpneqps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 4)
#define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5)
#define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5)
#define cmpnltps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 5)
#define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6)
#define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6)
#define cmpnleps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 6)
#define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7)
#define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7)
#define cmpordps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 7)
/* Lowest Field of 4x32f Parallel CoMPares
(resulting fields are either 0 or -1)
*/
#define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op)
#define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op)
#define cmpss(vars, vard, op, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, op)
#define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0)
#define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0)
#define cmpeqss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 0)
#define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1)
#define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1)
#define cmpltss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 1)
#define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2)
#define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2)
#define cmpless(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 2)
#define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3)
#define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3)
#define cmpunordss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 3)
#define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4)
#define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4)
#define cmpneqss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 4)
#define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5)
#define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5)
#define cmpnltss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 5)
#define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6)
#define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6)
#define cmpnless(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 6)
#define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7)
#define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7)
#define cmpordss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 7)
/* Lowest Field of 4x32f Parallel CoMPares to set EFLAGS
(resulting fields are either 0 or -1)
*/
#define comiss_m2r(var, reg) sse_m2r(comiss, var, reg)
#define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd)
#define comiss(vars, vard, xmmreg) sse_m2m(comiss, vars, vard, xmmreg)
/* Lowest Field of 4x32f Unordered Parallel CoMPares to set EFLAGS
(resulting fields are either 0 or -1)
*/
#define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg)
#define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd)
#define ucomiss(vars, vard, xmmreg) sse_m2m(ucomiss, vars, vard, xmmreg)
/* 2-(4x32f) -> 4x32f UNPaCK Low Packed Single-fp
(interleaves low half of dest with low half of source
as padding in each result field)
*/
#define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg)
#define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd)
/* 2-(4x32f) -> 4x32f UNPaCK High Packed Single-fp
(interleaves high half of dest with high half of source
as padding in each result field)
*/
#define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg)
#define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd)
/* Fp and mmX ReSTORe state
*/
#ifdef SSE_TRACE
#define fxrstor(mem) \
{ \
fprintf(stderr, "fxrstor()\n"); \
__asm__ __volatile__ ("fxrstor %0" \
: /* nothing */ \
: "X" (mem)) \
}
#else
#define fxrstor(mem) \
__asm__ __volatile__ ("fxrstor %0" \
: /* nothing */ \
: "X" (mem))
#endif
/* Fp and mmX SAVE state
*/
#ifdef SSE_TRACE
#define fxsave(mem) \
{ \
fprintf(stderr, "fxsave()\n"); \
__asm__ __volatile__ ("fxsave %0" \
: /* nothing */ \
: "X" (mem)) \
}
#else
#define fxsave(mem) \
__asm__ __volatile__ ("fxsave %0" \
: /* nothing */ \
: "X" (mem))
#endif
/* STore streaMing simd eXtensions Control/Status Register
*/
#ifdef SSE_TRACE
#define stmxcsr(mem) \
{ \
fprintf(stderr, "stmxcsr()\n"); \
__asm__ __volatile__ ("stmxcsr %0" \
: /* nothing */ \
: "X" (mem)) \
}
#else
#define stmxcsr(mem) \
__asm__ __volatile__ ("stmxcsr %0" \
: /* nothing */ \
: "X" (mem))
#endif
/* LoaD streaMing simd eXtensions Control/Status Register
*/
#ifdef SSE_TRACE
#define ldmxcsr(mem) \
{ \
fprintf(stderr, "ldmxcsr()\n"); \
__asm__ __volatile__ ("ldmxcsr %0" \
: /* nothing */ \
: "X" (mem)) \
}
#else
#define ldmxcsr(mem) \
__asm__ __volatile__ ("ldmxcsr %0" \
: /* nothing */ \
: "X" (mem))
#endif
/* Store FENCE - enforce ordering of stores before fence vs. stores
occuring after fence in source code.
*/
#ifdef SSE_TRACE
#define sfence() \
{ \
fprintf(stderr, "sfence()\n"); \
__asm__ __volatile__ ("sfence\n\t") \
}
#else
#define sfence() \
__asm__ __volatile__ ("sfence\n\t")
#endif
/* PREFETCH data using T0, T1, T2, or NTA hint
T0 = Prefetch into all cache levels
T1 = Prefetch into all cache levels except 0th level
T2 = Prefetch into all cache levels except 0th and 1st levels
NTA = Prefetch data into non-temporal cache structure
*/
#ifdef SSE_TRACE
#else
#define prefetch(mem, hint) \
__asm__ __volatile__ ("prefetch" #hint " %0" \
: /* nothing */ \
: "X" (mem))
#define prefetcht0(mem) prefetch(mem, t0)
#define prefetcht1(mem) prefetch(mem, t1)
#define prefetcht2(mem) prefetch(mem, t2)
#define prefetchnta(mem) prefetch(mem, nta)
#endif
#endif

View file

@ -0,0 +1,187 @@
/**
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
*
* This program 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, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "gst/gst.h"
#include "gstdeinterlace2.h"
#include "plugins.h"
#include "speedy.h"
#include "tomsmocomp.h"
#include "tomsmocomp/tomsmocompmacros.h"
#include "x86-64_macros.inc"
#define SearchEffortDefault 5
#define UseStrangeBobDefault 0
long SearchEffort;
int UseStrangeBob;
MEMCPY_FUNC *pMyMemcpy;
int IsOdd;
const unsigned char *pWeaveSrc;
const unsigned char *pWeaveSrcP;
unsigned char *pWeaveDest;
const unsigned char *pCopySrc;
const unsigned char *pCopySrcP;
unsigned char *pCopyDest;
int src_pitch;
int dst_pitch;
int rowsize;
int height;
int FldHeight;
int
Fieldcopy (void *dest, const void *src, size_t count,
int rows, int dst_pitch, int src_pitch)
{
unsigned char *pDest = (unsigned char *) dest;
unsigned char *pSrc = (unsigned char *) src;
int i;
for (i = 0; i < rows; i++) {
pMyMemcpy (pDest, pSrc, count);
pSrc += src_pitch;
pDest += dst_pitch;
}
return 0;
}
#define IS_MMX
#define SSE_TYPE MMX
#define FUNCT_NAME tomsmocompDScaler_MMX
#include "tomsmocomp/TomsMoCompAll.inc"
#undef IS_MMX
#undef SSE_TYPE
#undef FUNCT_NAME
#define IS_3DNOW
#define SSE_TYPE 3DNOW
#define FUNCT_NAME tomsmocompDScaler_3DNOW
#include "tomsmocomp/TomsMoCompAll.inc"
#undef IS_3DNOW
#undef SSE_TYPE
#undef FUNCT_NAME
#define IS_SSE
#define SSE_TYPE SSE
#define FUNCT_NAME tomsmocompDScaler_SSE
#include "tomsmocomp/TomsMoCompAll.inc"
#undef IS_SSE
#undef SSE_TYPE
#undef FUNCT_NAME
void
deinterlace_frame_di_tomsmocomp (GstDeinterlace2 * object)
{
if (object->cpu_feature_flags & OIL_IMPL_FLAG_SSE) {
tomsmocomp_filter_sse (object);
} else if (object->cpu_feature_flags & OIL_IMPL_FLAG_3DNOW) {
tomsmocomp_filter_3dnow (object);
} else {
tomsmocomp_filter_mmx (object);
}
}
static deinterlace_method_t tomsmocompmethod = {
0, //DEINTERLACE_PLUGIN_API_VERSION,
"Motion Adaptive: Motion Search",
"AdaptiveSearch",
4,
OIL_IMPL_FLAG_MMX,
0,
0,
0,
0,
0,
0,
deinterlace_frame_di_tomsmocomp,
{"Uses heuristics to detect motion in the input",
"frames and reconstruct image detail where",
"possible. Use this for high quality output",
"even on monitors set to an arbitrary refresh",
"rate.",
"",
"Motion search mode finds and follows motion",
"vectors for accurate interpolation. This is",
"the TomsMoComp deinterlacer from DScaler.",
""}
};
deinterlace_method_t *
dscaler_tomsmocomp_get_method (void)
{
tomsmocomp_init ();
return &tomsmocompmethod;
}
void
tomsmocomp_init (void)
{
SearchEffort = SearchEffortDefault;
UseStrangeBob = UseStrangeBobDefault;
}
void
tomsmocomp_filter_mmx (GstDeinterlace2 * object)
{
tomsmocompDScaler_MMX (object);
}
void
tomsmocomp_filter_3dnow (GstDeinterlace2 * object)
{
tomsmocompDScaler_3DNOW (object);
}
void
tomsmocomp_filter_sse (GstDeinterlace2 * object)
{
tomsmocompDScaler_SSE (object);
}

View file

@ -0,0 +1,61 @@
/**
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
*
* This program 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, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef TOMSMOCOMP_H_INCLUDED
#define TOMSMOCOMP_H_INCLUDED
#include "gstdeinterlace2.h"
#ifdef __cplusplus
extern "C" {
#endif
int Search_Effort_0();
int Search_Effort_1();
int Search_Effort_3();
int Search_Effort_5();
int Search_Effort_9();
int Search_Effort_11();
int Search_Effort_13();
int Search_Effort_15();
int Search_Effort_19();
int Search_Effort_21();
int Search_Effort_Max();
int Search_Effort_0_SB();
int Search_Effort_1_SB();
int Search_Effort_3_SB();
int Search_Effort_5_SB();
int Search_Effort_9_SB();
int Search_Effort_11_SB();
int Search_Effort_13_SB();
int Search_Effort_15_SB();
int Search_Effort_19_SB();
int Search_Effort_21_SB();
int Search_Effort_Max_SB();
void tomsmocomp_init( void );
void tomsmocomp_filter_mmx( GstDeinterlace2 *object );
void tomsmocomp_filter_3dnow( GstDeinterlace2 *object );
void tomsmocomp_filter_sse( GstDeinterlace2 *object );
#ifdef __cplusplus
};
#endif
#endif /* TOMSMOCOMP_H_INCLUDED */

View file

@ -0,0 +1,184 @@
/*
*
* GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* This file contains code from ffmpeg, see http://ffmpeg.org/ (LGPL)
* and modifications by Billy Biggs.
*
* Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
#include <stdio.h>
#if defined (__SVR4) && defined (__sun)
# include <sys/int_types.h>
#else
# include <stdint.h>
#endif
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "mmx.h"
#include "speedy.h"
#include "gstdeinterlace2.h"
/**
* The MPEG2 spec uses a slightly harsher filter, they specify
* [-1 8 2 8 -1]. ffmpeg uses a similar filter but with more of
* a tendancy to blur than to use the local information. The
* filter taps here are: [-1 4 2 4 -1].
*/
static void
deinterlace_line (uint8_t * dst, uint8_t * lum_m4,
uint8_t * lum_m3, uint8_t * lum_m2,
uint8_t * lum_m1, uint8_t * lum, int size)
{
#ifdef HAVE_CPU_I386
mmx_t rounder;
rounder.uw[0] = 4;
rounder.uw[1] = 4;
rounder.uw[2] = 4;
rounder.uw[3] = 4;
pxor_r2r (mm7, mm7);
movq_m2r (rounder, mm6);
for (; size > 3; size -= 4) {
movd_m2r (lum_m4[0], mm0);
movd_m2r (lum_m3[0], mm1);
movd_m2r (lum_m2[0], mm2);
movd_m2r (lum_m1[0], mm3);
movd_m2r (lum[0], mm4);
punpcklbw_r2r (mm7, mm0);
punpcklbw_r2r (mm7, mm1);
punpcklbw_r2r (mm7, mm2);
punpcklbw_r2r (mm7, mm3);
punpcklbw_r2r (mm7, mm4);
paddw_r2r (mm3, mm1);
psllw_i2r (1, mm2);
paddw_r2r (mm4, mm0);
psllw_i2r (2, mm1); // 2
paddw_r2r (mm6, mm2);
paddw_r2r (mm2, mm1);
psubusw_r2r (mm0, mm1);
psrlw_i2r (3, mm1); // 3
packuswb_r2r (mm7, mm1);
movd_r2m (mm1, dst[0]);
lum_m4 += 4;
lum_m3 += 4;
lum_m2 += 4;
lum_m1 += 4;
lum += 4;
dst += 4;
}
emms ();
#else
/**
* C implementation.
*/
int sum;
for (; size > 0; size--) {
sum = -lum_m4[0];
sum += lum_m3[0] << 2;
sum += lum_m2[0] << 1;
sum += lum_m1[0] << 2;
sum += -lum[0];
dst[0] = (sum + 4) >> 3; // This needs to be clipped at 0 and 255: cm[(sum + 4) >> 3];
lum_m4++;
lum_m3++;
lum_m2++;
lum_m1++;
lum++;
dst++;
}
#endif
}
/**
* The commented-out method below that uses the bottom_field member is more
* like the filter as specified in the MPEG2 spec, but it doesn't seem to
* have the desired effect.
*/
static void
deinterlace_scanline_vfir (GstDeinterlace2 * object,
deinterlace_scanline_data_t * data, uint8_t * output)
{
deinterlace_line (output, data->tt1, data->t0, data->m1, data->b0, data->bb1,
object->frame_width * 2);
// blit_packed422_scanline( output, data->m1, width );
}
static void
copy_scanline (GstDeinterlace2 * object,
deinterlace_scanline_data_t * data, uint8_t * output)
{
blit_packed422_scanline (output, data->m0, object->frame_width);
/*
if( data->bottom_field ) {
deinterlace_line( output, data->tt2, data->t1, data->m2, data->b1, data->bb2, width*2 );
} else {
deinterlace_line( output, data->tt0, data->t1, data->m0, data->b1, data->bb0, width*2 );
}
*/
}
static deinterlace_method_t vfirmethod = {
0, //DEINTERLACE_PLUGIN_API_VERSION,
"Blur: Vertical",
"BlurVertical",
2,
#ifdef HAVE_CPU_I386
OIL_IMPL_FLAG_MMXEXT,
#else
0,
#endif
0,
0,
0,
1,
deinterlace_scanline_vfir,
copy_scanline,
0,
{"Avoids flicker by blurring consecutive frames",
"of input. Use this if you want to run your",
"monitor at an arbitrary refresh rate and not",
"use much CPU, and are willing to sacrifice",
"detail.",
"",
"Vertical mode blurs favouring the most recent",
"field for less visible trails. From the",
"deinterlacer filter in ffmpeg.",
""}
};
deinterlace_method_t *
dscaler_vfir_get_method (void)
{
return &vfirmethod;
}

View file

@ -0,0 +1,82 @@
/*
*
* GStreamer
* Copyright (C) 2004 Dirk Ziegelmeier <dziegel@gmx.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
*
* See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
*/
/*
* This file is copied from TVTIME's sources.
* Original author: Achim Schneider <batchall@mordor.ch>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef XAX
#if defined (HAVE_CPU_I386) && !defined(HAVE_CPU_X86_64)
#define XAX "eax"
#define XBX "ebx"
#define XCX "ecx"
#define XDX "edx"
#define XSI "esi"
#define XDI "edi"
#define XSP "esp"
#define MOVX "movl"
#define LEAX "leal"
#define DECX "decl"
#define PUSHX "pushl"
#define POPX "popl"
#define CMPX "cmpl"
#define ADDX "addl"
#define SHLX "shll"
#define SHRX "shrl"
#define SUBX "subl"
#elif defined (HAVE_CPU_X86_64)
#define XAX "rax"
#define XBX "rbx"
#define XCX "rcx"
#define XDX "rdx"
#define XSI "rsi"
#define XDI "rdi"
#define XSP "rsp"
#define MOVX "movq"
#define LEAX "leaq"
#define DECX "decq"
#define PUSHX "pushq"
#define POPX "popq"
#define CMPX "cmpq"
#define ADDX "addq"
#define SHLX "shlq"
#define SHRX "shrq"
#define SUBX "subq"
#else
#error Undefined architecture. Define either ARCH_X86 or ARCH_X86_64.
#endif
#endif