deinterlace: Refactor deinterlacing as preparation for supporting more color formats

This commit is contained in:
Sebastian Dröge 2010-04-21 17:00:05 +02:00
parent e2eb012a41
commit 3dc7215492
15 changed files with 839 additions and 590 deletions

View file

@ -2,10 +2,10 @@ plugin_LTLIBRARIES = libgstdeinterlace.la
libgstdeinterlace_la_SOURCES = \ libgstdeinterlace_la_SOURCES = \
gstdeinterlace.c \ gstdeinterlace.c \
tvtime/tomsmocomp.c \
tvtime/greedy.c \ tvtime/greedy.c \
tvtime/greedyh.c \ tvtime/greedyh.c \
tvtime/vfir.c \ tvtime/vfir.c \
tvtime/tomsmocomp.c \
tvtime/weavetff.c \ tvtime/weavetff.c \
tvtime/weavebff.c \ tvtime/weavebff.c \
tvtime/weave.c \ tvtime/weave.c \

View file

@ -1,7 +1,7 @@
/* /*
* GStreamer * GStreamer
* Copyright (C) 2005 Martin Eikermann <meiker@upb.de> * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
* Copyright (C) 2008-2009 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -70,25 +70,104 @@ enum
G_DEFINE_TYPE (GstDeinterlaceMethod, gst_deinterlace_method, GST_TYPE_OBJECT); G_DEFINE_TYPE (GstDeinterlaceMethod, gst_deinterlace_method, GST_TYPE_OBJECT);
static gboolean
gst_deinterlace_method_supported (GType type, GstVideoFormat format, gint width,
gint height)
{
GstDeinterlaceMethodClass *klass =
GST_DEINTERLACE_METHOD_CLASS (g_type_class_ref (type));
gboolean ret;
if (format == GST_VIDEO_FORMAT_UNKNOWN)
ret = TRUE;
else
ret = klass->supported (klass, format, width, height);
g_type_class_unref (klass);
return ret;
}
static gboolean
gst_deinterlace_method_supported_impl (GstDeinterlaceMethodClass * klass,
GstVideoFormat format, gint width, gint height)
{
switch (format) {
case GST_VIDEO_FORMAT_YUY2:
return (klass->deinterlace_frame_yuy2 != NULL);
case GST_VIDEO_FORMAT_YVYU:
return (klass->deinterlace_frame_yvyu != NULL);
default:
return FALSE;
}
}
static void
gst_deinterlace_method_setup (GstDeinterlaceMethod * self,
GstVideoFormat format, gint width, gint height)
{
GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
klass->setup (self, format, width, height);
}
static void
gst_deinterlace_method_setup_impl (GstDeinterlaceMethod * self,
GstVideoFormat format, gint width, gint height)
{
gint i;
GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
self->format = format;
self->frame_width = width;
self->frame_height = height;
self->deinterlace_frame = NULL;
if (format == GST_VIDEO_FORMAT_UNKNOWN)
return;
for (i = 0; i < 4; i++) {
self->width[i] = gst_video_format_get_component_width (format, i, width);
self->height[i] = gst_video_format_get_component_height (format, i, height);
self->offset[i] =
gst_video_format_get_component_offset (format, i, width, height);
self->row_stride[i] = gst_video_format_get_row_stride (format, i, width);
self->pixel_stride[i] = gst_video_format_get_pixel_stride (format, i);
}
switch (format) {
case GST_VIDEO_FORMAT_YUY2:
self->deinterlace_frame = klass->deinterlace_frame_yuy2;
break;
case GST_VIDEO_FORMAT_YVYU:
self->deinterlace_frame = klass->deinterlace_frame_yvyu;
break;
default:
self->deinterlace_frame = NULL;
break;
}
}
static void static void
gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass) gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass)
{ {
klass->setup = gst_deinterlace_method_setup_impl;
klass->supported = gst_deinterlace_method_supported_impl;
} }
static void static void
gst_deinterlace_method_init (GstDeinterlaceMethod * self) gst_deinterlace_method_init (GstDeinterlaceMethod * self)
{ {
self->format = GST_VIDEO_FORMAT_UNKNOWN;
} }
static void static void
gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self, gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
GstDeinterlace * parent, GstBuffer * outbuf) const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
{ {
GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self); g_assert (self->deinterlace_frame != NULL);
self->deinterlace_frame (self, history, history_count, outbuf);
klass->deinterlace_frame (self, parent, outbuf);
} }
static gint static gint
@ -107,144 +186,215 @@ gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self)
return klass->latency; return klass->latency;
} }
G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method, G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method,
GST_TYPE_DEINTERLACE_METHOD); GST_TYPE_DEINTERLACE_METHOD);
static void static gboolean
gst_deinterlace_simple_method_interpolate_scanline (GstDeinterlaceMethod * self, gst_deinterlace_simple_method_supported (GstDeinterlaceMethodClass * mklass,
GstDeinterlace * parent, guint8 * out, GstVideoFormat format, gint width, gint height)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
oil_memcpy (out, scanlines->m1, parent->row_stride); GstDeinterlaceSimpleMethodClass *klass =
GST_DEINTERLACE_SIMPLE_METHOD_CLASS (mklass);
if (!GST_DEINTERLACE_METHOD_CLASS
(gst_deinterlace_simple_method_parent_class)->supported (mklass, format,
width, height))
return FALSE;
switch (format) {
case GST_VIDEO_FORMAT_YUY2:
return (klass->interpolate_scanline_yuy2 != NULL
&& klass->copy_scanline_yuy2 != NULL);
case GST_VIDEO_FORMAT_YVYU:
return (klass->interpolate_scanline_yvyu != NULL
&& klass->copy_scanline_yvyu != NULL);
default:
return FALSE;
}
} }
static void static void
gst_deinterlace_simple_method_copy_scanline (GstDeinterlaceMethod * self, gst_deinterlace_simple_method_interpolate_scanline_packed
GstDeinterlace * parent, guint8 * out, (GstDeinterlaceSimpleMethod * self, guint8 * out,
GstDeinterlaceScanlineData * scanlines, gint width) const GstDeinterlaceScanlineData * scanlines)
{ {
oil_memcpy (out, scanlines->m0, parent->row_stride); oil_memcpy (out, scanlines->m1, self->parent.row_stride[0]);
} }
static void static void
gst_deinterlace_simple_method_deinterlace_frame (GstDeinterlaceMethod * self, gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod *
GstDeinterlace * parent, GstBuffer * outbuf) self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{ {
GstDeinterlaceSimpleMethodClass *dsm_class = oil_memcpy (out, scanlines->m0, self->parent.row_stride[0]);
GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self); }
static void
gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
method, const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
{
GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self); GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
GstDeinterlaceScanlineData scanlines; GstDeinterlaceScanlineData scanlines;
guint8 *out = GST_BUFFER_DATA (outbuf); guint8 *out = GST_BUFFER_DATA (outbuf);
guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL; guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL;
gint cur_field_idx = parent->history_count - dm_class->fields_required; gint cur_field_idx = history_count - dm_class->fields_required;
guint cur_field_flags = parent->field_history[cur_field_idx].flags; guint cur_field_flags = history[cur_field_idx].flags;
gint line; gint line;
gint field_height = self->parent.frame_height / 2;
gint row_stride = self->parent.row_stride[0];
gint field_stride = self->parent.row_stride[0] * 2;
field0 = GST_BUFFER_DATA (parent->field_history[cur_field_idx].buf); g_assert (self->interpolate_scanline_packed != NULL);
g_assert (self->copy_scanline_packed != NULL);
field0 = GST_BUFFER_DATA (history[cur_field_idx].buf);
if (history[cur_field_idx].flags & PICTURE_INTERLACED_BOTTOM)
field0 += row_stride;
g_return_if_fail (dm_class->fields_required <= 4); g_return_if_fail (dm_class->fields_required <= 4);
if (dm_class->fields_required >= 2) if (dm_class->fields_required >= 2) {
field1 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 1].buf); field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf);
if (dm_class->fields_required >= 3) if (history[cur_field_idx + 1].flags & PICTURE_INTERLACED_BOTTOM)
field2 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 2].buf); field1 += row_stride;
if (dm_class->fields_required >= 4) }
field3 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 3].buf);
if (dm_class->fields_required >= 3) {
field2 = GST_BUFFER_DATA (history[cur_field_idx + 2].buf);
if (history[cur_field_idx + 2].flags & PICTURE_INTERLACED_BOTTOM)
field2 += row_stride;
}
if (dm_class->fields_required >= 4) {
field3 = GST_BUFFER_DATA (history[cur_field_idx + 3].buf);
if (history[cur_field_idx + 3].flags & PICTURE_INTERLACED_BOTTOM)
field3 += row_stride;
}
if (cur_field_flags == PICTURE_INTERLACED_BOTTOM) { if (cur_field_flags == PICTURE_INTERLACED_BOTTOM) {
/* double the first scanline of the bottom field */ /* double the first scanline of the bottom field */
oil_memcpy (out, field0, parent->row_stride); oil_memcpy (out, field0, row_stride);
out += parent->row_stride; out += row_stride;
} }
oil_memcpy (out, field0, parent->row_stride); oil_memcpy (out, field0, row_stride);
out += parent->row_stride; out += row_stride;
for (line = 2; line <= parent->field_height; line++) { for (line = 2; line <= field_height; line++) {
memset (&scanlines, 0, sizeof (scanlines)); memset (&scanlines, 0, sizeof (scanlines));
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM); scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
/* interp. scanline */ /* interp. scanline */
scanlines.t0 = field0; scanlines.t0 = field0;
scanlines.b0 = field0 + parent->field_stride; scanlines.b0 = field0 + field_stride;
if (field1 != NULL) { if (field1 != NULL) {
scanlines.tt1 = field1; scanlines.tt1 = field1;
scanlines.m1 = field1 + parent->field_stride; scanlines.m1 = field1 + field_stride;
scanlines.bb1 = field1 + parent->field_stride * 2; scanlines.bb1 = field1 + field_stride * 2;
field1 += parent->field_stride; field1 += field_stride;
} }
if (field2 != NULL) { if (field2 != NULL) {
scanlines.t2 = field2; scanlines.t2 = field2;
scanlines.b2 = field2 + parent->field_stride; scanlines.b2 = field2 + field_stride;
} }
if (field3 != NULL) { if (field3 != NULL) {
scanlines.tt3 = field3; scanlines.tt3 = field3;
scanlines.m3 = field3 + parent->field_stride; scanlines.m3 = field3 + field_stride;
scanlines.bb3 = field3 + parent->field_stride * 2; scanlines.bb3 = field3 + field_stride * 2;
field3 += parent->field_stride; field3 += field_stride;
} }
/* set valid data for corner cases */ /* set valid data for corner cases */
if (line == 2) { if (line == 2) {
scanlines.tt1 = scanlines.bb1; scanlines.tt1 = scanlines.bb1;
scanlines.tt3 = scanlines.bb3; scanlines.tt3 = scanlines.bb3;
} else if (line == parent->field_height) { } else if (line == field_height) {
scanlines.bb1 = scanlines.tt1; scanlines.bb1 = scanlines.tt1;
scanlines.bb3 = scanlines.tt3; scanlines.bb3 = scanlines.tt3;
} }
dsm_class->interpolate_scanline (self, parent, out, &scanlines, self->interpolate_scanline_packed (self, out, &scanlines);
parent->frame_width); out += row_stride;
out += parent->row_stride;
memset (&scanlines, 0, sizeof (scanlines)); memset (&scanlines, 0, sizeof (scanlines));
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM); scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
/* copy a scanline */ /* copy a scanline */
scanlines.tt0 = field0; scanlines.tt0 = field0;
scanlines.m0 = field0 + parent->field_stride; scanlines.m0 = field0 + field_stride;
scanlines.bb0 = field0 + parent->field_stride * 2; scanlines.bb0 = field0 + field_stride * 2;
field0 += parent->field_stride; field0 += field_stride;
if (field1 != NULL) { if (field1 != NULL) {
scanlines.t1 = field1; scanlines.t1 = field1;
scanlines.b1 = field1 + parent->field_stride; scanlines.b1 = field1 + field_stride;
} }
if (field2 != NULL) { if (field2 != NULL) {
scanlines.tt2 = field2; scanlines.tt2 = field2;
scanlines.m2 = field2 + parent->field_stride; scanlines.m2 = field2 + field_stride;
scanlines.bb2 = field2 + parent->field_stride * 2; scanlines.bb2 = field2 + field_stride * 2;
field2 += parent->field_stride; field2 += field_stride;
} }
if (field3 != NULL) { if (field3 != NULL) {
scanlines.t3 = field3; scanlines.t3 = field3;
scanlines.b3 = field3 + parent->field_stride; scanlines.b3 = field3 + field_stride;
} }
/* set valid data for corner cases */ /* set valid data for corner cases */
if (line == parent->field_height) { if (line == field_height) {
scanlines.bb0 = scanlines.tt0; scanlines.bb0 = scanlines.tt0;
scanlines.b1 = scanlines.t1; scanlines.b1 = scanlines.t1;
scanlines.bb2 = scanlines.tt2; scanlines.bb2 = scanlines.tt2;
scanlines.b3 = scanlines.t3; scanlines.b3 = scanlines.t3;
} }
dsm_class->copy_scanline (self, parent, out, &scanlines, self->copy_scanline_packed (self, out, &scanlines);
parent->frame_width); out += row_stride;
out += parent->row_stride;
} }
if (cur_field_flags == PICTURE_INTERLACED_TOP) { if (cur_field_flags == PICTURE_INTERLACED_TOP) {
/* double the last scanline of the top field */ /* double the last scanline of the top field */
oil_memcpy (out, field0, parent->row_stride); oil_memcpy (out, field0, row_stride);
}
}
static void
gst_deinterlace_simple_method_setup (GstDeinterlaceMethod * method,
GstVideoFormat format, gint width, gint height)
{
GstDeinterlaceSimpleMethod *self = GST_DEINTERLACE_SIMPLE_METHOD (method);
GstDeinterlaceSimpleMethodClass *klass =
GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self);
GST_DEINTERLACE_METHOD_CLASS
(gst_deinterlace_simple_method_parent_class)->setup (method, format,
width, height);
self->interpolate_scanline_packed = NULL;
self->copy_scanline_packed = NULL;
if (format == GST_VIDEO_FORMAT_UNKNOWN)
return;
switch (format) {
case GST_VIDEO_FORMAT_YUY2:
self->interpolate_scanline_packed = klass->interpolate_scanline_yuy2;
self->copy_scanline_packed = klass->copy_scanline_yuy2;
break;
case GST_VIDEO_FORMAT_YVYU:
self->interpolate_scanline_packed = klass->interpolate_scanline_yvyu;
self->copy_scanline_packed = klass->copy_scanline_yvyu;
break;
default:
break;
} }
} }
@ -254,12 +404,22 @@ gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass *
{ {
GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass; GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
dm_class->deinterlace_frame = gst_deinterlace_simple_method_deinterlace_frame; dm_class->deinterlace_frame_yuy2 =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_yvyu =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->fields_required = 2; dm_class->fields_required = 2;
dm_class->setup = gst_deinterlace_simple_method_setup;
dm_class->supported = gst_deinterlace_simple_method_supported;
klass->interpolate_scanline = klass->interpolate_scanline_yuy2 =
gst_deinterlace_simple_method_interpolate_scanline; gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline = gst_deinterlace_simple_method_copy_scanline; klass->copy_scanline_yuy2 =
gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_yvyu =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_yvyu =
gst_deinterlace_simple_method_copy_scanline_packed;
} }
static void static void
@ -417,59 +577,81 @@ _do_init (GType object_type)
GST_BOILERPLATE_FULL (GstDeinterlace, gst_deinterlace, GstElement, GST_BOILERPLATE_FULL (GstDeinterlace, gst_deinterlace, GstElement,
GST_TYPE_ELEMENT, _do_init); GST_TYPE_ELEMENT, _do_init);
static const struct
{
GType (*get_type) (void);
} _method_types[] = {
{
gst_deinterlace_method_tomsmocomp_get_type}, {
gst_deinterlace_method_greedy_h_get_type}, {
gst_deinterlace_method_greedy_l_get_type}, {
gst_deinterlace_method_vfir_get_type}, {
gst_deinterlace_method_linear_get_type}, {
gst_deinterlace_method_linear_blend_get_type}, {
gst_deinterlace_method_scaler_bob_get_type}, {
gst_deinterlace_method_weave_get_type}, {
gst_deinterlace_method_weave_tff_get_type}, {
gst_deinterlace_method_weave_bff_get_type}
};
static void static void
gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method) gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
{ {
GType method_type;
GST_DEBUG_OBJECT (self, "Setting new method %d", method); GST_DEBUG_OBJECT (self, "Setting new method %d", method);
if (self->method) { if (self->method) {
if (self->method_id == method &&
gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
self->format, self->width, self->height)) {
GST_DEBUG_OBJECT (self, "Reusing current method");
return;
}
gst_child_proxy_child_removed (GST_OBJECT (self), gst_child_proxy_child_removed (GST_OBJECT (self),
GST_OBJECT (self->method)); GST_OBJECT (self->method));
gst_object_unparent (GST_OBJECT (self->method)); gst_object_unparent (GST_OBJECT (self->method));
self->method = NULL; self->method = NULL;
} }
switch (method) { method_type =
case GST_DEINTERLACE_TOMSMOCOMP: _method_types[method].get_type !=
self->method = g_object_new (GST_TYPE_DEINTERLACE_TOMSMOCOMP, NULL); NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
break; if (method_type == G_TYPE_INVALID
case GST_DEINTERLACE_GREEDY_H: || !gst_deinterlace_method_supported (method_type, self->format,
self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_H, NULL); self->width, self->height)) {
break; GType tmp;
case GST_DEINTERLACE_GREEDY_L: gint i;
self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_L, NULL);
break; method_type = G_TYPE_INVALID;
case GST_DEINTERLACE_VFIR:
self->method = g_object_new (GST_TYPE_DEINTERLACE_VFIR, NULL); GST_WARNING_OBJECT (self, "Method doesn't support requested format");
break; for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
case GST_DEINTERLACE_LINEAR: if (_method_types[i].get_type == NULL)
self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR, NULL); continue;
break; tmp = _method_types[i].get_type ();
case GST_DEINTERLACE_LINEAR_BLEND: if (gst_deinterlace_method_supported (tmp, self->format, self->width,
self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR_BLEND, NULL); self->height)) {
break; GST_DEBUG_OBJECT (self, "Using method %d", i);
case GST_DEINTERLACE_SCALER_BOB: method_type = tmp;
self->method = g_object_new (GST_TYPE_DEINTERLACE_SCALER_BOB, NULL); break;
break; }
case GST_DEINTERLACE_WEAVE: }
self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE, NULL); /* If we get here we must have invalid caps! */
break; g_assert (method_type != G_TYPE_INVALID);
case GST_DEINTERLACE_WEAVE_TFF:
self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_TFF, NULL);
break;
case GST_DEINTERLACE_WEAVE_BFF:
self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_BFF, NULL);
break;
default:
GST_WARNING_OBJECT (self, "Invalid Deinterlacer Method");
return;
} }
self->method = g_object_new (method_type, NULL);
self->method_id = method; self->method_id = method;
gst_object_set_name (GST_OBJECT (self->method), "method"); gst_object_set_name (GST_OBJECT (self->method), "method");
gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self)); gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method)); gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
if (self->method)
gst_deinterlace_method_setup (self->method, self->format, self->width,
self->height);
} }
static gboolean static gboolean
@ -757,7 +939,7 @@ gst_deinterlace_reset_history (GstDeinterlace * self)
} }
} }
memset (self->field_history, 0, memset (self->field_history, 0,
GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstPicture)); GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
self->history_count = 0; self->history_count = 0;
if (self->last_buffer) if (self->last_buffer)
@ -770,13 +952,11 @@ gst_deinterlace_reset (GstDeinterlace * self)
{ {
GST_DEBUG_OBJECT (self, "Resetting internal state"); GST_DEBUG_OBJECT (self, "Resetting internal state");
self->row_stride = 0; self->format = GST_VIDEO_FORMAT_UNKNOWN;
self->frame_width = 0; self->width = 0;
self->frame_height = 0; self->height = 0;
self->frame_rate_n = 0; self->frame_size = 0;
self->frame_rate_d = 0; self->fps_n = self->fps_d = 0;
self->field_height = 0;
self->field_stride = 0;
gst_segment_init (&self->segment, GST_FORMAT_TIME); gst_segment_init (&self->segment, GST_FORMAT_TIME);
@ -948,13 +1128,11 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
GST_DEBUG_OBJECT (self, "Top field first"); GST_DEBUG_OBJECT (self, "Top field first");
field1 = gst_buffer_ref (buffer); field1 = gst_buffer_ref (buffer);
field1_flags = PICTURE_INTERLACED_TOP; field1_flags = PICTURE_INTERLACED_TOP;
field2 = gst_buffer_create_sub (buffer, self->row_stride, field2 = gst_buffer_ref (buffer);
GST_BUFFER_SIZE (buffer) - self->row_stride);
field2_flags = PICTURE_INTERLACED_BOTTOM; field2_flags = PICTURE_INTERLACED_BOTTOM;
} else { } else {
GST_DEBUG_OBJECT (self, "Bottom field first"); GST_DEBUG_OBJECT (self, "Bottom field first");
field1 = gst_buffer_create_sub (buffer, self->row_stride, field1 = gst_buffer_ref (buffer);
GST_BUFFER_SIZE (buffer) - self->row_stride);
field1_flags = PICTURE_INTERLACED_BOTTOM; field1_flags = PICTURE_INTERLACED_BOTTOM;
field2 = gst_buffer_ref (buffer); field2 = gst_buffer_ref (buffer);
field2_flags = PICTURE_INTERLACED_TOP; field2_flags = PICTURE_INTERLACED_TOP;
@ -1172,7 +1350,8 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
ret = GST_FLOW_OK; ret = GST_FLOW_OK;
} else { } else {
/* do magic calculus */ /* do magic calculus */
gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf); gst_deinterlace_method_deinterlace_frame (self->method,
self->field_history, self->history_count, outbuf);
gst_buffer_unref (gst_deinterlace_pop_history (self)); gst_buffer_unref (gst_deinterlace_pop_history (self));
@ -1249,7 +1428,8 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
ret = GST_FLOW_OK; ret = GST_FLOW_OK;
} else { } else {
/* do magic calculus */ /* do magic calculus */
gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf); gst_deinterlace_method_deinterlace_frame (self->method,
self->field_history, self->history_count, outbuf);
gst_buffer_unref (gst_deinterlace_pop_history (self)); gst_buffer_unref (gst_deinterlace_pop_history (self));
@ -1476,33 +1656,23 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
gboolean res = TRUE; gboolean res = TRUE;
GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad)); GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
GstPad *otherpad; GstPad *otherpad;
GstStructure *structure;
GstVideoFormat fmt;
guint32 fourcc;
GstCaps *othercaps; GstCaps *othercaps;
otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad; otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
structure = gst_caps_get_structure (caps, 0); res =
gst_video_format_parse_caps (caps, &self->format, &self->width,
res = gst_structure_get_int (structure, "width", &self->frame_width); &self->height);
res &= gst_structure_get_int (structure, "height", &self->frame_height); res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
res &= if (pad == self->sinkpad)
gst_structure_get_fraction (structure, "framerate", &self->frame_rate_n,
&self->frame_rate_d);
res &= gst_structure_get_fourcc (structure, "format", &fourcc);
if (pad == self->sinkpad) {
res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced); res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
} else {
res &= gst_video_format_parse_caps_interlaced (caps, &self->src_interlaced);
}
if (!res) if (!res)
goto invalid_caps; goto invalid_caps;
if ((self->interlaced || self->mode == GST_DEINTERLACE_MODE_INTERLACED) && if ((self->interlaced || self->mode == GST_DEINTERLACE_MODE_INTERLACED) &&
self->fields == GST_DEINTERLACE_ALL self->fields == GST_DEINTERLACE_ALL
&& self->mode != GST_DEINTERLACE_MODE_DISABLED) { && self->mode != GST_DEINTERLACE_MODE_DISABLED) {
gint fps_n = self->frame_rate_n, fps_d = self->frame_rate_d; gint fps_n = self->fps_n, fps_d = self->fps_d;
if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad)) if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad))
goto invalid_caps; goto invalid_caps;
@ -1516,39 +1686,22 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
} }
if (otherpad == self->srcpad && self->mode != GST_DEINTERLACE_MODE_DISABLED) { if (otherpad == self->srcpad && self->mode != GST_DEINTERLACE_MODE_DISABLED) {
GstStructure *s;
othercaps = gst_caps_make_writable (othercaps); othercaps = gst_caps_make_writable (othercaps);
s = gst_caps_get_structure (othercaps, 0); gst_caps_set_simple (othercaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
gst_structure_remove_field (s, "interlaced");
} }
if (!gst_pad_set_caps (otherpad, othercaps)) if (!gst_pad_set_caps (otherpad, othercaps))
goto caps_not_accepted; goto caps_not_accepted;
self->field_height = self->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 */
self->field_stride =
gst_video_format_get_row_stride (fmt, 0, self->frame_width) * 2;
/* in bytes */
self->row_stride =
gst_video_format_get_row_stride (fmt, 0, self->frame_width);
self->frame_size = self->frame_size =
gst_video_format_get_size (fmt, self->frame_width, self->frame_height); gst_video_format_get_size (self->format, self->width, self->height);
if (self->fields == GST_DEINTERLACE_ALL && otherpad == self->srcpad) if (self->fields == GST_DEINTERLACE_ALL && otherpad == self->srcpad)
self->field_duration = self->field_duration =
gst_util_uint64_scale (GST_SECOND, self->frame_rate_d, gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
self->frame_rate_n);
else else
self->field_duration = self->field_duration =
gst_util_uint64_scale (GST_SECOND, self->frame_rate_d, gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
2 * self->frame_rate_n);
if (pad == self->sinkpad) { if (pad == self->sinkpad) {
gst_caps_replace (&self->sink_caps, caps); gst_caps_replace (&self->sink_caps, caps);
@ -1558,6 +1711,10 @@ gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
gst_caps_replace (&self->sink_caps, othercaps); gst_caps_replace (&self->sink_caps, othercaps);
} }
gst_deinterlace_set_method (self, self->method_id);
gst_deinterlace_method_setup (self->method, self->format, self->width,
self->height);
GST_DEBUG_OBJECT (pad, "Set caps: %" GST_PTR_FORMAT, caps); GST_DEBUG_OBJECT (pad, "Set caps: %" GST_PTR_FORMAT, caps);
GST_DEBUG_OBJECT (pad, "Other caps: %" GST_PTR_FORMAT, othercaps); GST_DEBUG_OBJECT (pad, "Other caps: %" GST_PTR_FORMAT, othercaps);

View file

@ -1,7 +1,7 @@
/* /*
* GStreamer * GStreamer
* Copyright (C) 2005 Martin Eikermann <meiker@upb.de> * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
* Copyright (C) 2008-2009 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -24,6 +24,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/video/video.h> #include <gst/video/video.h>
#include <liboil/liboil.h> #include <liboil/liboil.h>
#include <liboil/liboilcpu.h> #include <liboil/liboilcpu.h>
#include <liboil/liboilfunction.h> #include <liboil/liboilfunction.h>
@ -61,12 +62,39 @@ typedef struct _GstDeinterlaceClass GstDeinterlaceClass;
typedef struct _GstDeinterlaceMethod GstDeinterlaceMethod; typedef struct _GstDeinterlaceMethod GstDeinterlaceMethod;
typedef struct _GstDeinterlaceMethodClass GstDeinterlaceMethodClass; typedef struct _GstDeinterlaceMethodClass GstDeinterlaceMethodClass;
#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 struct
{
/* pointer to the start of data for this field */
GstBuffer *buf;
/* see PICTURE_ flags in *.c */
guint flags;
} GstDeinterlaceField;
/* /*
* This structure defines the deinterlacer plugin. * This structure defines the deinterlacer plugin.
*/ */
typedef void (*GstDeinterlaceMethodDeinterlaceFunction) (GstDeinterlaceMethod *self, const GstDeinterlaceField *history, guint history_count, GstBuffer *outbuf);
struct _GstDeinterlaceMethod { struct _GstDeinterlaceMethod {
GstObject parent; GstObject parent;
GstVideoFormat format;
gint frame_width, frame_height;
gint width[4];
gint height[4];
gint offset[4];
gint row_stride[4];
gint pixel_stride[4];
GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame;
}; };
struct _GstDeinterlaceMethodClass { struct _GstDeinterlaceMethodClass {
@ -74,7 +102,12 @@ struct _GstDeinterlaceMethodClass {
guint fields_required; guint fields_required;
guint latency; guint latency;
void (*deinterlace_frame) (GstDeinterlaceMethod *self, GstDeinterlace * parent, GstBuffer *outbuf); gboolean (*supported) (GstDeinterlaceMethodClass *klass, GstVideoFormat format, gint width, gint height);
void (*setup) (GstDeinterlaceMethod *self, GstVideoFormat format, gint width, gint height);
GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_yuy2;
GstDeinterlaceMethodDeinterlaceFunction deinterlace_frame_yvyu;
const gchar *name; const gchar *name;
const gchar *nick; const gchar *nick;
@ -99,10 +132,10 @@ typedef struct _GstDeinterlaceScanlineData GstDeinterlaceScanlineData;
*/ */
struct _GstDeinterlaceScanlineData { struct _GstDeinterlaceScanlineData {
guint8 *tt0, *t0, *m0, *b0, *bb0; const guint8 *tt0, *t0, *m0, *b0, *bb0;
guint8 *tt1, *t1, *m1, *b1, *bb1; const guint8 *tt1, *t1, *m1, *b1, *bb1;
guint8 *tt2, *t2, *m2, *b2, *bb2; const guint8 *tt2, *t2, *m2, *b2, *bb2;
guint8 *tt3, *t3, *m3, *b3, *bb3; const guint8 *tt3, *t3, *m3, *b3, *bb3;
gboolean bottom_field; gboolean bottom_field;
}; };
@ -130,35 +163,29 @@ struct _GstDeinterlaceScanlineData {
* All other values are NULL. * All other values are NULL.
*/ */
typedef void (*GstDeinterlaceSimpleMethodPackedFunction) (GstDeinterlaceSimpleMethod *self, guint8 *out, const GstDeinterlaceScanlineData *scanlines);
struct _GstDeinterlaceSimpleMethod { struct _GstDeinterlaceSimpleMethod {
GstDeinterlaceMethod parent; GstDeinterlaceMethod parent;
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_packed;
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_packed;
}; };
struct _GstDeinterlaceSimpleMethodClass { struct _GstDeinterlaceSimpleMethodClass {
GstDeinterlaceMethodClass parent_class; GstDeinterlaceMethodClass parent_class;
void (*interpolate_scanline) (GstDeinterlaceMethod *self, GstDeinterlace * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width); /* Packed formats */
void (*copy_scanline) (GstDeinterlaceMethod *self, GstDeinterlace * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width); GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_yuy2;
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_yuy2;
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_yvyu;
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_yvyu;
}; };
GType gst_deinterlace_simple_method_get_type (void); GType gst_deinterlace_simple_method_get_type (void);
#define GST_DEINTERLACE_MAX_FIELD_HISTORY 10 #define GST_DEINTERLACE_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 struct
{
/* pointer to the start of data for this field */
GstBuffer *buf;
/* see PICTURE_ flags in *.c */
guint flags;
} GstPicture;
typedef enum typedef enum
{ {
GST_DEINTERLACE_TOMSMOCOMP, GST_DEINTERLACE_TOMSMOCOMP,
@ -210,42 +237,20 @@ struct _GstDeinterlace
GstDeinterlaceMethods method_id; GstDeinterlaceMethods method_id;
GstDeinterlaceMethod *method; GstDeinterlaceMethod *method;
guint frame_size; GstVideoFormat format;
gint frame_rate_n, frame_rate_d; gint width, height; /* frame width & height */
gboolean interlaced; guint frame_size; /* frame size in bytes */
gboolean src_interlaced; gint fps_n, fps_d; /* frame rate */
gboolean interlaced; /* is input interlaced? */
/* Number of bytes of actual data in each scanline. May be less than GstClockTime field_duration; /* Duration of one field */
OverlayPitch since the overlay's scanlines might have alignment
requirements. Generally equal to FrameWidth * 2.
*/
guint row_stride;
/* 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;
/* distance between lines in image
need not match the pixel width
*/
guint field_stride;
/* Duration of one field */
GstClockTime field_duration;
/* The most recent pictures /* The most recent pictures
PictureHistory[0] is always the most recent. PictureHistory[0] is always the most recent.
Pointers are NULL if the picture in question isn't valid, e.g. because Pointers are NULL if the picture in question isn't valid, e.g. because
the program just started or a picture was skipped. the program just started or a picture was skipped.
*/ */
GstPicture field_history[GST_DEINTERLACE_MAX_FIELD_HISTORY]; GstDeinterlaceField field_history[GST_DEINTERLACE_MAX_FIELD_HISTORY];
guint history_count; guint history_count;
/* Set to TRUE if we're in still frame mode, /* Set to TRUE if we're in still frame mode,
@ -278,4 +283,5 @@ struct _GstDeinterlaceClass
GType gst_deinterlace_get_type (void); GType gst_deinterlace_get_type (void);
G_END_DECLS G_END_DECLS
#endif /* __GST_DEINTERLACE_H__ */ #endif /* __GST_DEINTERLACE_H__ */

View file

@ -4,7 +4,7 @@
* Copyright (c) 2000 Tom Barry All rights reserved. * Copyright (c) 2000 Tom Barry All rights reserved.
* mmx.h port copyright (c) 2002 Billy Biggs <vektor@dumbterm.net>. * mmx.h port copyright (c) 2002 Billy Biggs <vektor@dumbterm.net>.
* *
* Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -32,8 +32,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -57,8 +55,9 @@ typedef struct
typedef struct typedef struct
{ {
GstDeinterlaceMethodClass parent_class; GstDeinterlaceMethodClass parent_class;
void (*scanline) (GstDeinterlaceMethodGreedyL * self, uint8_t * L2, void (*scanline) (GstDeinterlaceMethodGreedyL * self, const guint8 * L2,
uint8_t * L1, uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size); const guint8 * L1, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
gint width);
} GstDeinterlaceMethodGreedyLClass; } GstDeinterlaceMethodGreedyLClass;
// This is a simple lightweight DeInterlace method that uses little CPU time // This is a simple lightweight DeInterlace method that uses little CPU time
@ -74,11 +73,11 @@ typedef struct
// Blended Clip but this give too good results for the CPU to ignore here. // Blended Clip but this give too good results for the CPU to ignore here.
static inline void static inline void
deinterlace_greedy_packed422_scanline_c (GstDeinterlaceMethodGreedyL * self, deinterlace_greedy_scanline_c (GstDeinterlaceMethodGreedyL * self,
uint8_t * m0, uint8_t * t1, const guint8 * m0, const guint8 * t1,
uint8_t * b1, uint8_t * m2, uint8_t * output, int width) const guint8 * b1, const guint8 * m2, guint8 * output, gint width)
{ {
int avg, l2_diff, lp2_diff, max, min, best; gint avg, l2_diff, lp2_diff, max, min, best;
guint max_comb = self->max_comb; guint max_comb = self->max_comb;
// L2 == m0 // L2 == m0
@ -124,9 +123,9 @@ deinterlace_greedy_packed422_scanline_c (GstDeinterlaceMethodGreedyL * self,
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
#include "mmx.h" #include "mmx.h"
static void static void
deinterlace_greedy_packed422_scanline_mmx (GstDeinterlaceMethodGreedyL * self, deinterlace_greedy_scanline_mmx (GstDeinterlaceMethodGreedyL * self,
uint8_t * m0, uint8_t * t1, const guint8 * m0, const guint8 * t1,
uint8_t * b1, uint8_t * m2, uint8_t * output, int width) const guint8 * b1, const guint8 * m2, guint8 * output, gint width)
{ {
mmx_t MaxComb; mmx_t MaxComb;
mmx_t ShiftMask; mmx_t ShiftMask;
@ -233,16 +232,15 @@ deinterlace_greedy_packed422_scanline_mmx (GstDeinterlaceMethodGreedyL * self,
} }
emms (); emms ();
if (width > 0) if (width > 0)
deinterlace_greedy_packed422_scanline_c (self, m0, t1, b1, m2, output, deinterlace_greedy_scanline_c (self, m0, t1, b1, m2, output, width);
width);
} }
#include "sse.h" #include "sse.h"
static void static void
deinterlace_greedy_packed422_scanline_mmxext (GstDeinterlaceMethodGreedyL * deinterlace_greedy_scanline_mmxext (GstDeinterlaceMethodGreedyL *
self, uint8_t * m0, uint8_t * t1, uint8_t * b1, uint8_t * m2, self, const guint8 * m0, const guint8 * t1, const guint8 * b1,
uint8_t * output, int width) const guint8 * m2, guint8 * output, gint width)
{ {
mmx_t MaxComb; mmx_t MaxComb;
@ -327,70 +325,80 @@ deinterlace_greedy_packed422_scanline_mmxext (GstDeinterlaceMethodGreedyL *
emms (); emms ();
if (width > 0) if (width > 0)
deinterlace_greedy_packed422_scanline_c (self, m0, t1, b1, m2, output, deinterlace_greedy_scanline_c (self, m0, t1, b1, m2, output, width);
width);
} }
#endif #endif
static void static void
deinterlace_frame_di_greedy (GstDeinterlaceMethod * d_method, deinterlace_frame_di_greedy_packed (GstDeinterlaceMethod * method,
GstDeinterlace * object, GstBuffer * outbuf) const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
{ {
GstDeinterlaceMethodGreedyL *self = GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (method);
GST_DEINTERLACE_METHOD_GREEDY_L (d_method);
GstDeinterlaceMethodGreedyLClass *klass = GstDeinterlaceMethodGreedyLClass *klass =
GST_DEINTERLACE_METHOD_GREEDY_L_GET_CLASS (self); GST_DEINTERLACE_METHOD_GREEDY_L_GET_CLASS (self);
int InfoIsOdd = 0; gint InfoIsOdd = 0;
int Line; gint Line;
unsigned int Pitch = object->field_stride; gint RowStride = method->row_stride[0];
unsigned char *L1; // ptr to Line1, of 3 gint FieldHeight = method->frame_height / 2;
unsigned char *L2; // ptr to Line2, the weave line gint Pitch = method->row_stride[0] * 2;
unsigned char *L3; // ptr to Line3 const guint8 *L1; // ptr to Line1, of 3
const guint8 *L2; // ptr to Line2, the weave line
unsigned char *L2P; // ptr to prev Line2 const guint8 *L3; // ptr to Line3
unsigned char *Dest = GST_BUFFER_DATA (outbuf); const guint8 *L2P; // ptr to prev Line2
guint8 *Dest = GST_BUFFER_DATA (outbuf);
// copy first even line no matter what, and the first odd line if we're // 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.) // processing an EVEN field. (note diff from other deint rtns.)
if (object->field_history[object->history_count - 1].flags == if (history[history_count - 1].flags == PICTURE_INTERLACED_BOTTOM) {
PICTURE_INTERLACED_BOTTOM) {
InfoIsOdd = 1; InfoIsOdd = 1;
L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); L1 = GST_BUFFER_DATA (history[history_count - 2].buf);
L2 = GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf); if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 += RowStride;
L2 = GST_BUFFER_DATA (history[history_count - 1].buf);
if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 += RowStride;
L3 = L1 + Pitch; L3 = L1 + Pitch;
L2P = L2P = GST_BUFFER_DATA (history[history_count - 3].buf);
GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf); if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P += RowStride;
// copy first even line // copy first even line
oil_memcpy (Dest, L1, object->row_stride); oil_memcpy (Dest, L1, RowStride);
Dest += object->row_stride; Dest += RowStride;
} else { } else {
InfoIsOdd = 0; InfoIsOdd = 0;
L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); L1 = GST_BUFFER_DATA (history[history_count - 2].buf);
L2 = GST_BUFFER_DATA (object->field_history[object->history_count - if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
1].buf) + Pitch; L1 += RowStride;
L2 = GST_BUFFER_DATA (history[history_count - 1].buf) + Pitch;
if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 += RowStride;
L3 = L1 + Pitch; L3 = L1 + Pitch;
L2P = L2P = GST_BUFFER_DATA (history[history_count - 3].buf) + Pitch;
GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf) + if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
Pitch; L2P += RowStride;
// copy first even line // copy first even line
oil_memcpy (Dest, GST_BUFFER_DATA (object->field_history[0].buf), oil_memcpy (Dest, GST_BUFFER_DATA (history[0].buf), RowStride);
object->row_stride); Dest += RowStride;
Dest += object->row_stride;
// then first odd line // then first odd line
oil_memcpy (Dest, L1, object->row_stride); oil_memcpy (Dest, L1, RowStride);
Dest += object->row_stride; Dest += RowStride;
} }
for (Line = 0; Line < (object->field_height - 1); ++Line) { for (Line = 0; Line < (FieldHeight - 1); ++Line) {
klass->scanline (self, L2, L1, L3, L2P, Dest, object->row_stride); klass->scanline (self, L2, L1, L3, L2P, Dest, RowStride);
Dest += object->row_stride; Dest += RowStride;
oil_memcpy (Dest, L3, object->row_stride); oil_memcpy (Dest, L3, RowStride);
Dest += object->row_stride; Dest += RowStride;
L1 += Pitch; L1 += Pitch;
L2 += Pitch; L2 += Pitch;
@ -399,18 +407,17 @@ deinterlace_frame_di_greedy (GstDeinterlaceMethod * d_method,
} }
if (InfoIsOdd) { if (InfoIsOdd) {
oil_memcpy (Dest, L2, object->row_stride); oil_memcpy (Dest, L2, RowStride);
} }
} }
G_DEFINE_TYPE (GstDeinterlaceMethodGreedyL, gst_deinterlace_method_greedy_l, G_DEFINE_TYPE (GstDeinterlaceMethodGreedyL, gst_deinterlace_method_greedy_l,
GST_TYPE_DEINTERLACE_METHOD); GST_TYPE_DEINTERLACE_METHOD);
enum enum
{ {
ARG_0, PROP_0,
ARG_MAX_COMB PROP_MAX_COMB
}; };
static void static void
@ -420,7 +427,7 @@ gst_deinterlace_method_greedy_l_set_property (GObject * object, guint prop_id,
GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object); GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object);
switch (prop_id) { switch (prop_id) {
case ARG_MAX_COMB: case PROP_MAX_COMB:
self->max_comb = g_value_get_uint (value); self->max_comb = g_value_get_uint (value);
break; break;
default: default:
@ -435,7 +442,7 @@ gst_deinterlace_method_greedy_l_get_property (GObject * object, guint prop_id,
GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object); GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object);
switch (prop_id) { switch (prop_id) {
case ARG_MAX_COMB: case PROP_MAX_COMB:
g_value_set_uint (value, self->max_comb); g_value_set_uint (value, self->max_comb);
break; break;
default: default:
@ -456,28 +463,30 @@ gst_deinterlace_method_greedy_l_class_init (GstDeinterlaceMethodGreedyLClass *
gobject_class->set_property = gst_deinterlace_method_greedy_l_set_property; gobject_class->set_property = gst_deinterlace_method_greedy_l_set_property;
gobject_class->get_property = gst_deinterlace_method_greedy_l_get_property; gobject_class->get_property = gst_deinterlace_method_greedy_l_get_property;
g_object_class_install_property (gobject_class, ARG_MAX_COMB, g_object_class_install_property (gobject_class, PROP_MAX_COMB,
g_param_spec_uint ("max-comb", g_param_spec_uint ("max-comb",
"Max comb", "Max comb",
"Max Comb", 0, 255, 15, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) "Max Comb", 0, 255, 15, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
); );
dim_class->fields_required = 4; dim_class->fields_required = 4;
dim_class->deinterlace_frame = deinterlace_frame_di_greedy;
dim_class->name = "Motion Adaptive: Simple Detection"; dim_class->name = "Motion Adaptive: Simple Detection";
dim_class->nick = "greedyl"; dim_class->nick = "greedyl";
dim_class->latency = 1; dim_class->latency = 1;
dim_class->deinterlace_frame_yuy2 = deinterlace_frame_di_greedy_packed;
dim_class->deinterlace_frame_yvyu = deinterlace_frame_di_greedy_packed;
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
klass->scanline = deinterlace_greedy_packed422_scanline_mmxext; klass->scanline = deinterlace_greedy_scanline_mmxext;
} else if (cpu_flags & OIL_IMPL_FLAG_MMX) { } else if (cpu_flags & OIL_IMPL_FLAG_MMX) {
klass->scanline = deinterlace_greedy_packed422_scanline_mmx; klass->scanline = deinterlace_greedy_scanline_mmx;
} else { } else {
klass->scanline = deinterlace_greedy_packed422_scanline_c; klass->scanline = deinterlace_greedy_scanline_c;
} }
#else #else
klass->scanline = deinterlace_greedy_packed422_scanline_c; klass->scanline = deinterlace_greedy_scanline_c;
#endif #endif
} }

View file

@ -2,7 +2,7 @@
* *
* GStreamer * GStreamer
* Copyright (c) 2001 Tom Barry. All rights reserved. * Copyright (c) 2001 Tom Barry. All rights reserved.
* Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -15,7 +15,7 @@
* Library General Public License for more details. * Library General Public License for more details.
* *
* You should have received a copy of the GNU Library General Public * You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the * License aglong with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
@ -30,29 +30,28 @@
#include "x86-64_macros.inc" #include "x86-64_macros.inc"
static void static void
FUNCT_NAME (GstDeinterlaceMethodGreedyH *self, uint8_t * L1, uint8_t * L2, uint8_t * L3, uint8_t * L2P, FUNCT_NAME (GstDeinterlaceMethodGreedyH *self, const guint8 * L1, const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest, gint width)
uint8_t * Dest, int size)
{ {
// in tight loop some vars are accessed faster in local storage // in tight loop some vars are accessed faster in local storage
int64_t YMask = 0x00ff00ff00ff00ffull; // to keep only luma gint64 YMask = 0x00ff00ff00ff00ffull; // to keep only luma
int64_t UVMask = 0xff00ff00ff00ff00ull; // to keep only chroma gint64 UVMask = 0xff00ff00ff00ff00ull; // to keep only chroma
int64_t ShiftMask = 0xfefefefefefefefeull; // to avoid shifting chroma to luma gint64 ShiftMask = 0xfefefefefefefefeull; // to avoid shifting chroma to luma
int64_t QW256 = 0x0100010001000100ull; // 4 256's gint64 QW256 = 0x0100010001000100ull; // 4 256's
int64_t MaxComb; gint64 MaxComb;
int64_t MotionThreshold; gint64 MotionThreshold;
int64_t MotionSense; gint64 MotionSense;
int64_t i; gint64 i;
long LoopCtr; glong LoopCtr;
long oldbx; glong oldbx;
gint64 QW256B;
gint64 LastAvg = 0; //interp value from left qword
int64_t QW256B;
int64_t LastAvg = 0; //interp value from left qword
// FIXME: Use C implementation if the width is not a multiple of 4 // FIXME: Use C implementation if the width is not a multiple of 4
// Do something more optimal later // Do something more optimal later
if (size % 8 != 0) if (width % 4 != 0)
greedyDScaler_C (self, L1, L2, L3, L2P, Dest, size); C_FUNCT (self, L1, L2, L3, L2P, Dest, width);
// Set up our two parms that are actually evaluated for each pixel // Set up our two parms that are actually evaluated for each pixel
i = self->max_comb; i = self->max_comb;
@ -68,7 +67,7 @@ FUNCT_NAME (GstDeinterlaceMethodGreedyH *self, uint8_t * L1, uint8_t * L2, uint8
i = 0xffffffff - 256; i = 0xffffffff - 256;
QW256B = i << 48 | i << 32 | i << 16 | i; // save a couple instr on PMINSW instruct. QW256B = i << 48 | i << 32 | i << 16 | i; // save a couple instr on PMINSW instruct.
LoopCtr = size / 8 - 1; // there are LineLength / 8 qwords per line but do 1 less, adj at end of loop LoopCtr = width / 4 - 1; // there are LineLength / 4 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 // 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.. // field (i.e., that InfoIsOdd is true). Assume the obvious for even lines..

View file

@ -2,7 +2,7 @@
* *
* GStreamer * GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net> * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
* Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -32,10 +32,9 @@
#include "greedyhmacros.h" #include "greedyhmacros.h"
#include <stdlib.h> #include <stdlib.h>
#include "_stdint.h"
#include <string.h> #include <string.h>
#include "gst/gst.h" #include <gst/gst.h>
#include "plugins.h" #include "plugins.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
@ -54,41 +53,45 @@ typedef struct
guint max_comb, motion_threshold, motion_sense; guint max_comb, motion_threshold, motion_sense;
} GstDeinterlaceMethodGreedyH; } GstDeinterlaceMethodGreedyH;
typedef void (*ScanlineFunction) (GstDeinterlaceMethodGreedyH * self,
const guint8 * L2, const guint8 * L1, const guint8 * L3, const guint8 * L2P,
guint8 * Dest, gint width);
typedef struct typedef struct
{ {
GstDeinterlaceMethodClass parent_class; GstDeinterlaceMethodClass parent_class;
void (*scanline) (GstDeinterlaceMethodGreedyH * self, uint8_t * L2, ScanlineFunction scanline_yuy2; /* This is for YVYU too */
uint8_t * L1, uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size);
} GstDeinterlaceMethodGreedyHClass; } GstDeinterlaceMethodGreedyHClass;
static void static void
greedyDScaler_C (GstDeinterlaceMethodGreedyH * self, uint8_t * L1, uint8_t * L2, greedyh_scanline_yuy2_C (GstDeinterlaceMethodGreedyH * self, const guint8 * L1,
uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size) const guint8 * L2, const guint8 * L3, const guint8 * L2P, guint8 * Dest,
gint width)
{ {
int Pos; gint Pos;
uint8_t l1_l, l1_1_l, l3_l, l3_1_l; guint8 l1_l, l1_1_l, l3_l, l3_1_l;
uint8_t l1_c, l1_1_c, l3_c, l3_1_c; guint8 l1_c, l1_1_c, l3_c, l3_1_c;
uint8_t avg_l, avg_c, avg_l_1, avg_c_1; guint8 avg_l, avg_c, avg_l_1, avg_c_1;
uint8_t avg_l__1 = 0, avg_c__1 = 0; guint8 avg_l__1 = 0, avg_c__1 = 0;
uint8_t avg_s_l, avg_s_c; guint8 avg_s_l, avg_s_c;
uint8_t avg_sc_l, avg_sc_c; guint8 avg_sc_l, avg_sc_c;
uint8_t best_l, best_c; guint8 best_l, best_c;
uint16_t mov_l; guint16 mov_l;
uint8_t out_l, out_c; guint8 out_l, out_c;
uint8_t l2_l, l2_c, lp2_l, lp2_c; guint8 l2_l, l2_c, lp2_l, lp2_c;
uint8_t l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff; guint8 l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff;
uint8_t min_l, min_c, max_l, max_c; guint8 min_l, min_c, max_l, max_c;
guint max_comb = self->max_comb; guint max_comb = self->max_comb;
guint motion_sense = self->motion_sense; guint motion_sense = self->motion_sense;
guint motion_threshold = self->motion_threshold; guint motion_threshold = self->motion_threshold;
for (Pos = 0; Pos < size; Pos += 2) { for (Pos = 0; Pos < width; Pos++) {
l1_l = L1[0]; l1_l = L1[0];
l1_c = L1[1]; l1_c = L1[1];
l3_l = L3[0]; l3_l = L3[0];
l3_c = L3[1]; l3_c = L3[1];
if (Pos == size - 1) { if (Pos == width - 1) {
l1_1_l = l1_l; l1_1_l = l1_l;
l1_1_c = l1_c; l1_1_c = l1_c;
l3_1_l = l3_l; l3_1_l = l3_l;
@ -207,7 +210,8 @@ greedyDScaler_C (GstDeinterlaceMethodGreedyH * self, uint8_t * L1, uint8_t * L2,
#define IS_MMXEXT #define IS_MMXEXT
#define SIMD_TYPE MMXEXT #define SIMD_TYPE MMXEXT
#define FUNCT_NAME greedyDScaler_MMXEXT #define C_FUNCT greedyh_scanline_yuy2_C
#define FUNCT_NAME greedyh_scanline_yuy2_MMXEXT
#include "greedyh.asm" #include "greedyh.asm"
#undef SIMD_TYPE #undef SIMD_TYPE
#undef IS_MMXEXT #undef IS_MMXEXT
@ -215,7 +219,7 @@ greedyDScaler_C (GstDeinterlaceMethodGreedyH * self, uint8_t * L1, uint8_t * L2,
#define IS_3DNOW #define IS_3DNOW
#define SIMD_TYPE 3DNOW #define SIMD_TYPE 3DNOW
#define FUNCT_NAME greedyDScaler_3DNOW #define FUNCT_NAME greedyh_scanline_yuy2_3DNOW
#include "greedyh.asm" #include "greedyh.asm"
#undef SIMD_TYPE #undef SIMD_TYPE
#undef IS_3DNOW #undef IS_3DNOW
@ -223,74 +227,95 @@ greedyDScaler_C (GstDeinterlaceMethodGreedyH * self, uint8_t * L1, uint8_t * L2,
#define IS_MMX #define IS_MMX
#define SIMD_TYPE MMX #define SIMD_TYPE MMX
#define FUNCT_NAME greedyDScaler_MMX #define FUNCT_NAME greedyh_scanline_yuy2_MMX
#include "greedyh.asm" #include "greedyh.asm"
#undef SIMD_TYPE #undef SIMD_TYPE
#undef IS_MMX #undef IS_MMX
#undef FUNCT_NAME #undef FUNCT_NAME
#undef C_FUNCT
#endif #endif
static void static void
deinterlace_frame_di_greedyh (GstDeinterlaceMethod * d_method, deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
GstDeinterlace * object, GstBuffer * outbuf) const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
{ {
GstDeinterlaceMethodGreedyH *self = GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
GST_DEINTERLACE_METHOD_GREEDY_H (d_method);
GstDeinterlaceMethodGreedyHClass *klass = GstDeinterlaceMethodGreedyHClass *klass =
GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self); GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
int InfoIsOdd = 0; gint InfoIsOdd = 0;
int Line; gint Line;
unsigned int Pitch = object->field_stride; gint RowStride = method->row_stride[0];
gint FieldHeight = method->frame_height / 2;
gint Pitch = method->row_stride[0] * 2;
const guint8 *L1; // ptr to Line1, of 3
const guint8 *L2; // ptr to Line2, the weave line
const guint8 *L3; // ptr to Line3
const guint8 *L2P; // ptr to prev Line2
guint8 *Dest = GST_BUFFER_DATA (outbuf);
ScanlineFunction scanline;
unsigned char *L1; // ptr to Line1, of 3 switch (method->format) {
unsigned char *L2; // ptr to Line2, the weave line case GST_VIDEO_FORMAT_YUY2:
unsigned char *L3; // ptr to Line3 case GST_VIDEO_FORMAT_YVYU:
scanline = klass->scanline_yuy2;
unsigned char *L2P; // ptr to prev Line2 break;
unsigned char *Dest = GST_BUFFER_DATA (outbuf); default:
g_assert_not_reached ();
break;
}
// copy first even line no matter what, and the first odd line if we're // 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.) // processing an EVEN field. (note diff from other deint rtns.)
if (object->field_history[object->history_count - 1].flags == if (history[history_count - 1].flags == PICTURE_INTERLACED_BOTTOM) {
PICTURE_INTERLACED_BOTTOM) {
InfoIsOdd = 1; InfoIsOdd = 1;
L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); L1 = GST_BUFFER_DATA (history[history_count - 2].buf);
L2 = GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf); if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 += RowStride;
L2 = GST_BUFFER_DATA (history[history_count - 1].buf);
if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 += RowStride;
L3 = L1 + Pitch; L3 = L1 + Pitch;
L2P = L2P = GST_BUFFER_DATA (history[history_count - 3].buf);
GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf); if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P += RowStride;
// copy first even line // copy first even line
oil_memcpy (Dest, L1, object->row_stride); oil_memcpy (Dest, L1, RowStride);
Dest += object->row_stride; Dest += RowStride;
} else { } else {
InfoIsOdd = 0; InfoIsOdd = 0;
L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf); L1 = GST_BUFFER_DATA (history[history_count - 2].buf);
L2 = GST_BUFFER_DATA (object->field_history[object->history_count - if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
1].buf) + Pitch; L1 += RowStride;
L2 = GST_BUFFER_DATA (history[history_count - 1].buf) + Pitch;
if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 += RowStride;
L3 = L1 + Pitch; L3 = L1 + Pitch;
L2P = L2P = GST_BUFFER_DATA (history[history_count - 3].buf) + Pitch;
GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf) + if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
Pitch; L2P += RowStride;
// copy first even line // copy first even line
oil_memcpy (Dest, oil_memcpy (Dest, L1, RowStride);
GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf), Dest += RowStride;
object->row_stride);
Dest += object->row_stride;
// then first odd line // then first odd line
oil_memcpy (Dest, L1, object->row_stride); oil_memcpy (Dest, L1, RowStride);
Dest += object->row_stride; Dest += RowStride;
} }
for (Line = 0; Line < (object->field_height - 1); ++Line) { for (Line = 0; Line < (FieldHeight - 1); ++Line) {
klass->scanline (self, L1, L2, L3, L2P, Dest, object->row_stride); scanline (self, L1, L2, L3, L2P, Dest, RowStride);
Dest += object->row_stride; Dest += RowStride;
oil_memcpy (Dest, L3, object->row_stride); oil_memcpy (Dest, L3, RowStride);
Dest += object->row_stride; Dest += RowStride;
L1 += Pitch; L1 += Pitch;
L2 += Pitch; L2 += Pitch;
@ -299,7 +324,7 @@ deinterlace_frame_di_greedyh (GstDeinterlaceMethod * d_method,
} }
if (InfoIsOdd) { if (InfoIsOdd) {
oil_memcpy (Dest, L2, object->row_stride); oil_memcpy (Dest, L2, RowStride);
} }
} }
@ -308,10 +333,10 @@ G_DEFINE_TYPE (GstDeinterlaceMethodGreedyH, gst_deinterlace_method_greedy_h,
enum enum
{ {
ARG_0, PROP_0,
ARG_MAX_COMB, PROP_MAX_COMB,
ARG_MOTION_THRESHOLD, PROP_MOTION_THRESHOLD,
ARG_MOTION_SENSE PROP_MOTION_SENSE
}; };
static void static void
@ -321,13 +346,13 @@ gst_deinterlace_method_greedy_h_set_property (GObject * object, guint prop_id,
GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object); GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
switch (prop_id) { switch (prop_id) {
case ARG_MAX_COMB: case PROP_MAX_COMB:
self->max_comb = g_value_get_uint (value); self->max_comb = g_value_get_uint (value);
break; break;
case ARG_MOTION_THRESHOLD: case PROP_MOTION_THRESHOLD:
self->motion_threshold = g_value_get_uint (value); self->motion_threshold = g_value_get_uint (value);
break; break;
case ARG_MOTION_SENSE: case PROP_MOTION_SENSE:
self->motion_sense = g_value_get_uint (value); self->motion_sense = g_value_get_uint (value);
break; break;
default: default:
@ -342,13 +367,13 @@ gst_deinterlace_method_greedy_h_get_property (GObject * object, guint prop_id,
GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object); GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
switch (prop_id) { switch (prop_id) {
case ARG_MAX_COMB: case PROP_MAX_COMB:
g_value_set_uint (value, self->max_comb); g_value_set_uint (value, self->max_comb);
break; break;
case ARG_MOTION_THRESHOLD: case PROP_MOTION_THRESHOLD:
g_value_set_uint (value, self->motion_threshold); g_value_set_uint (value, self->motion_threshold);
break; break;
case ARG_MOTION_SENSE: case PROP_MOTION_SENSE:
g_value_set_uint (value, self->motion_sense); g_value_set_uint (value, self->motion_sense);
break; break;
default: default:
@ -369,20 +394,20 @@ gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass *
gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property; gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property;
gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property; gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property;
g_object_class_install_property (gobject_class, ARG_MAX_COMB, g_object_class_install_property (gobject_class, PROP_MAX_COMB,
g_param_spec_uint ("max-comb", g_param_spec_uint ("max-comb",
"Max comb", "Max comb",
"Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) "Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
); );
g_object_class_install_property (gobject_class, ARG_MOTION_THRESHOLD, g_object_class_install_property (gobject_class, PROP_MOTION_THRESHOLD,
g_param_spec_uint ("motion-threshold", g_param_spec_uint ("motion-threshold",
"Motion Threshold", "Motion Threshold",
"Motion Threshold", "Motion Threshold",
0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) 0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
); );
g_object_class_install_property (gobject_class, ARG_MOTION_SENSE, g_object_class_install_property (gobject_class, PROP_MOTION_SENSE,
g_param_spec_uint ("motion-sense", g_param_spec_uint ("motion-sense",
"Motion Sense", "Motion Sense",
"Motion Sense", "Motion Sense",
@ -390,23 +415,25 @@ gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass *
); );
dim_class->fields_required = 4; dim_class->fields_required = 4;
dim_class->deinterlace_frame = deinterlace_frame_di_greedyh;
dim_class->name = "Motion Adaptive: Advanced Detection"; dim_class->name = "Motion Adaptive: Advanced Detection";
dim_class->nick = "greedyh"; dim_class->nick = "greedyh";
dim_class->latency = 1; dim_class->latency = 1;
dim_class->deinterlace_frame_yuy2 = deinterlace_frame_di_greedyh_packed;
dim_class->deinterlace_frame_yvyu = deinterlace_frame_di_greedyh_packed;
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
klass->scanline = greedyDScaler_MMXEXT; klass->scanline_yuy2 = greedyh_scanline_yuy2_MMXEXT;
} else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) { } else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) {
klass->scanline = greedyDScaler_3DNOW; klass->scanline_yuy2 = greedyh_scanline_yuy2_3DNOW;
} else if (cpu_flags & OIL_IMPL_FLAG_MMX) { } else if (cpu_flags & OIL_IMPL_FLAG_MMX) {
klass->scanline = greedyDScaler_MMX; klass->scanline_yuy2 = greedyh_scanline_yuy2_MMX;
} else { } else {
klass->scanline = greedyDScaler_C; klass->scanline_yuy2 = greedyh_scanline_yuy2_C;
} }
#else #else
klass->scanline = greedyDScaler_C; klass->scanline_yuy2 = greedyh_scanline_yuy2_C;
#endif #endif
} }

View file

@ -1,6 +1,6 @@
/** /**
* Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>. * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
* Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -27,7 +27,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -42,33 +41,36 @@
GType gst_deinterlace_method_linear_get_type (void); GType gst_deinterlace_method_linear_get_type (void);
typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinear; typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinear;
typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearClass; typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearClass;
static void static void
deinterlace_scanline_linear_c (GstDeinterlaceMethod * self, deinterlace_scanline_linear_c (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const guint8 * s1, const guint8 * s2, gint size)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
gint i; gint i;
width *= 2; for (i = 0; i < size; i++)
for (i = 0; i < width; i++) out[i] = (s1[i] + s2[i]) / 2;
out[i] = (scanlines->t0[i] + scanlines->b0[i]) / 2; }
static void
deinterlace_scanline_linear_packed_c (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
deinterlace_scanline_linear_c (self, out, scanlines->t0, scanlines->b0,
self->parent.row_stride[0]);
} }
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
#include "mmx.h" #include "mmx.h"
static void static void
deinterlace_scanline_linear_mmx (GstDeinterlaceMethod * self, deinterlace_scanline_linear_mmx (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const guint8 * bot, const guint8 * top, gint size)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
const mmx_t shiftmask = { 0xfefffefffefffeffULL }; /* To avoid shifting chroma to luma. */ const mmx_t shiftmask = { 0xfefffefffefffeffULL }; /* To avoid shifting chroma to luma. */
int i; int i;
guint8 *bot = scanlines->b0, *top = scanlines->t0;
for (i = width / 16; i; --i) { for (i = size / 32; i; --i) {
movq_m2r (*bot, mm0); movq_m2r (*bot, mm0);
movq_m2r (*top, mm1); movq_m2r (*top, mm1);
movq_m2r (*(bot + 8), mm2); movq_m2r (*(bot + 8), mm2);
@ -105,9 +107,9 @@ deinterlace_scanline_linear_mmx (GstDeinterlaceMethod * self,
top += 32; top += 32;
bot += 32; bot += 32;
} }
width = (width & 0xf); size = (size & 0x1f);
for (i = width / 4; i; --i) { for (i = size / 8; i; --i) {
movq_m2r (*bot, mm0); movq_m2r (*bot, mm0);
movq_m2r (*top, mm1); movq_m2r (*top, mm1);
pand_m2r (shiftmask, mm0); pand_m2r (shiftmask, mm0);
@ -120,26 +122,32 @@ deinterlace_scanline_linear_mmx (GstDeinterlaceMethod * self,
top += 8; top += 8;
bot += 8; bot += 8;
} }
width = width & 0x7; emms ();
size = size & 0xf;
/* Handle last few pixels. */ /* Handle last few pixels. */
for (i = width * 2; i; --i) { for (i = size; i; --i) {
*out++ = ((*top++) + (*bot++)) >> 1; *out++ = ((*top++) + (*bot++)) >> 1;
} }
}
emms (); static void
deinterlace_scanline_linear_packed_mmx (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
deinterlace_scanline_linear_mmx (self, out, scanlines->t0, scanlines->b0,
self->parent.row_stride[0]);
} }
#include "sse.h" #include "sse.h"
static void static void
deinterlace_scanline_linear_mmxext (GstDeinterlaceMethod * self, deinterlace_scanline_linear_mmxext (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const guint8 * bot, const guint8 * top, gint size)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
gint i; gint i;
guint8 *bot = scanlines->b0, *top = scanlines->t0;
for (i = width / 16; i; --i) { for (i = size / 32; i; --i) {
movq_m2r (*bot, mm0); movq_m2r (*bot, mm0);
movq_m2r (*top, mm1); movq_m2r (*top, mm1);
movq_m2r (*(bot + 8), mm2); movq_m2r (*(bot + 8), mm2);
@ -160,9 +168,9 @@ deinterlace_scanline_linear_mmxext (GstDeinterlaceMethod * self,
top += 32; top += 32;
bot += 32; bot += 32;
} }
width = (width & 0xf); size = (size & 0x1f);
for (i = width / 4; i; --i) { for (i = size / 8; i; --i) {
movq_m2r (*bot, mm0); movq_m2r (*bot, mm0);
movq_m2r (*top, mm1); movq_m2r (*top, mm1);
pavgb_r2r (mm1, mm0); pavgb_r2r (mm1, mm0);
@ -171,14 +179,22 @@ deinterlace_scanline_linear_mmxext (GstDeinterlaceMethod * self,
top += 8; top += 8;
bot += 8; bot += 8;
} }
width = width & 0x7; emms ();
size = size & 0xf;
/* Handle last few pixels. */ /* Handle last few pixels. */
for (i = width * 2; i; --i) { for (i = size; i; --i) {
*out++ = ((*top++) + (*bot++)) >> 1; *out++ = ((*top++) + (*bot++)) >> 1;
} }
}
emms (); static void
deinterlace_scanline_linear_packed_mmxext (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
deinterlace_scanline_linear_mmxext (self, out, scanlines->t0, scanlines->b0,
self->parent.row_stride[0]);
} }
#endif #endif
@ -202,13 +218,20 @@ gst_deinterlace_method_linear_class_init (GstDeinterlaceMethodLinearClass *
dim_class->nick = "linear"; dim_class->nick = "linear";
dim_class->latency = 0; dim_class->latency = 0;
dism_class->interpolate_scanline = deinterlace_scanline_linear_c; dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_linear_packed_c;
dism_class->interpolate_scanline_yvyu = deinterlace_scanline_linear_packed_c;
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
dism_class->interpolate_scanline = deinterlace_scanline_linear_mmxext; dism_class->interpolate_scanline_yuy2 =
} else if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { deinterlace_scanline_linear_packed_mmxext;
dism_class->interpolate_scanline = deinterlace_scanline_linear_mmx; dism_class->interpolate_scanline_yvyu =
deinterlace_scanline_linear_packed_mmxext;
} else if (cpu_flags & OIL_IMPL_FLAG_MMX) {
dism_class->interpolate_scanline_yuy2 =
deinterlace_scanline_linear_packed_mmx;
dism_class->interpolate_scanline_yvyu =
deinterlace_scanline_linear_packed_mmx;
} }
#endif #endif
} }

View file

@ -4,7 +4,7 @@
* sources. * sources.
* *
* Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>. * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
* Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -31,7 +31,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -46,57 +45,55 @@
GType gst_deinterlace_method_linear_blend_get_type (void); GType gst_deinterlace_method_linear_blend_get_type (void);
typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinearBlend; typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinearBlend;
typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearBlendClass; typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearBlendClass;
static inline void static inline void
deinterlace_scanline_linear_blend_c (GstDeinterlaceMethod * self, deinterlace_scanline_linear_blend_c (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const guint8 * t0, const guint8 * b0, const guint8 * m1,
GstDeinterlaceScanlineData * scanlines, gint width) gint size)
{ {
guint8 *t0 = scanlines->t0; while (size--) {
guint8 *b0 = scanlines->b0;
guint8 *m1 = scanlines->m1;
width *= 2;
while (width--) {
*out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2; *out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2;
} }
} }
static inline void static void
deinterlace_scanline_linear_blend2_c (GstDeinterlaceMethod * self, deinterlace_scanline_linear_blend_packed_c (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
guint8 *m0 = scanlines->m0; deinterlace_scanline_linear_blend_c (self, out, scanlines->t0, scanlines->b0,
guint8 *t1 = scanlines->t1; scanlines->m1, self->parent.row_stride[0]);
guint8 *b1 = scanlines->b1; }
width *= 2; static inline void
while (width--) { deinterlace_scanline_linear_blend2_c (GstDeinterlaceSimpleMethod * self,
guint8 * out, const guint8 * m0, const guint8 * t1, const guint8 * b1,
gint size)
{
while (size--) {
*out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2; *out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2;
} }
} }
static void
deinterlace_scanline_linear_blend2_packed_c (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
deinterlace_scanline_linear_blend2_c (self, out, scanlines->m0, scanlines->t1,
scanlines->b1, self->parent.row_stride[0]);
}
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
#include "mmx.h" #include "mmx.h"
static inline void static inline void
deinterlace_scanline_linear_blend_mmx (GstDeinterlaceMethod * self, deinterlace_scanline_linear_blend_mmx (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const guint8 * t0, const guint8 * b0, const guint8 * m1,
GstDeinterlaceScanlineData * scanlines, gint width) gint size)
{ {
guint8 *t0 = scanlines->t0;
guint8 *b0 = scanlines->b0;
guint8 *m1 = scanlines->m1;
gint i; gint i;
// Get width in bytes. i = size / 8;
width *= 2; size -= i * 8;
i = width / 8;
width -= i * 8;
pxor_r2r (mm7, mm7); pxor_r2r (mm7, mm7);
while (i--) { while (i--) {
@ -134,26 +131,29 @@ deinterlace_scanline_linear_blend_mmx (GstDeinterlaceMethod * self,
b0 += 8; b0 += 8;
m1 += 8; m1 += 8;
} }
while (width--) { emms ();
while (size--) {
*out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2; *out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2;
} }
emms (); }
static void
deinterlace_scanline_linear_blend_packed_mmx (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
deinterlace_scanline_linear_blend_mmx (self, out, scanlines->t0,
scanlines->b0, scanlines->m1, self->parent.row_stride[0]);
} }
static inline void static inline void
deinterlace_scanline_linear_blend2_mmx (GstDeinterlaceMethod * self, deinterlace_scanline_linear_blend2_mmx (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const guint8 * m0, const guint8 * t1, const guint8 * b1,
GstDeinterlaceScanlineData * scanlines, gint width) gint size)
{ {
guint8 *m0 = scanlines->m0;
guint8 *t1 = scanlines->t1;
guint8 *b1 = scanlines->b1;
gint i; gint i;
// Get width in bytes. i = size / 8;
width *= 2; size -= i * 8;
i = width / 8;
width -= i * 8;
pxor_r2r (mm7, mm7); pxor_r2r (mm7, mm7);
while (i--) { while (i--) {
@ -191,10 +191,19 @@ deinterlace_scanline_linear_blend2_mmx (GstDeinterlaceMethod * self,
b1 += 8; b1 += 8;
m0 += 8; m0 += 8;
} }
while (width--) { emms ();
while (size--) {
*out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2; *out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2;
} }
emms (); }
static void
deinterlace_scanline_linear_blend2_packed_mmx (GstDeinterlaceSimpleMethod *
self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
deinterlace_scanline_linear_blend2_mmx (self, out, scanlines->m0,
scanlines->t1, scanlines->b1, self->parent.row_stride[0]);
} }
#endif #endif
@ -218,13 +227,23 @@ static void
dim_class->nick = "linearblend"; dim_class->nick = "linearblend";
dim_class->latency = 0; dim_class->latency = 0;
dism_class->interpolate_scanline = deinterlace_scanline_linear_blend_c; dism_class->interpolate_scanline_yuy2 =
dism_class->copy_scanline = deinterlace_scanline_linear_blend2_c; deinterlace_scanline_linear_blend_packed_c;
dism_class->interpolate_scanline_yvyu =
deinterlace_scanline_linear_blend_packed_c;
dism_class->copy_scanline_yuy2 = deinterlace_scanline_linear_blend2_packed_c;
dism_class->copy_scanline_yvyu = deinterlace_scanline_linear_blend2_packed_c;
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
if (cpu_flags & OIL_IMPL_FLAG_MMX) { if (cpu_flags & OIL_IMPL_FLAG_MMX) {
dism_class->interpolate_scanline = deinterlace_scanline_linear_blend_mmx; dism_class->interpolate_scanline_yuy2 =
dism_class->copy_scanline = deinterlace_scanline_linear_blend2_mmx; deinterlace_scanline_linear_blend_packed_mmx;
dism_class->interpolate_scanline_yvyu =
deinterlace_scanline_linear_blend_packed_mmx;
dism_class->copy_scanline_yuy2 =
deinterlace_scanline_linear_blend2_packed_mmx;
dism_class->copy_scanline_yvyu =
deinterlace_scanline_linear_blend2_packed_mmx;
} }
#endif #endif
} }

View file

@ -1,6 +1,6 @@
/** /**
* Double lines * Double lines
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -22,7 +22,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -37,16 +36,13 @@
GType gst_deinterlace_method_scaler_bob_get_type (void); GType gst_deinterlace_method_scaler_bob_get_type (void);
typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodScalerBob; typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodScalerBob;
typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodScalerBobClass; typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodScalerBobClass;
static void static void
deinterlace_scanline_scaler_bob (GstDeinterlaceMethod * self, deinterlace_scanline_scaler_bob_packed (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
oil_memcpy (out, scanlines->t0, parent->row_stride); oil_memcpy (out, scanlines->t0, self->parent.row_stride[0]);
} }
G_DEFINE_TYPE (GstDeinterlaceMethodScalerBob, gst_deinterlace_method_scaler_bob, G_DEFINE_TYPE (GstDeinterlaceMethodScalerBob, gst_deinterlace_method_scaler_bob,
@ -65,7 +61,10 @@ gst_deinterlace_method_scaler_bob_class_init (GstDeinterlaceMethodScalerBobClass
dim_class->nick = "scalerbob"; dim_class->nick = "scalerbob";
dim_class->latency = 0; dim_class->latency = 0;
dism_class->interpolate_scanline = deinterlace_scanline_scaler_bob; dism_class->interpolate_scanline_yuy2 =
deinterlace_scanline_scaler_bob_packed;
dism_class->interpolate_scanline_yvyu =
deinterlace_scanline_scaler_bob_packed;
} }
static void static void

View file

@ -1,6 +1,6 @@
/** /**
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net> * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
* Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -28,10 +28,9 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include "_stdint.h"
#include <string.h> #include <string.h>
#include "gst/gst.h" #include <gst/gst.h>
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include "plugins.h" #include "plugins.h"
@ -51,26 +50,19 @@ typedef struct
gboolean strange_bob; gboolean strange_bob;
} GstDeinterlaceMethodTomsMoComp; } GstDeinterlaceMethodTomsMoComp;
typedef struct typedef GstDeinterlaceMethodClass GstDeinterlaceMethodTomsMoCompClass;
{
GstDeinterlaceMethodClass parent_class;
} GstDeinterlaceMethodTomsMoCompClass;
static int static void
Fieldcopy (void *dest, const void *src, size_t count, Fieldcopy (guint8 * dest, const guint8 * src, gint count,
int rows, int dst_pitch, int src_pitch) gint rows, gint dst_pitch, gint src_pitch)
{ {
unsigned char *pDest = (unsigned char *) dest; gint i;
unsigned char *pSrc = (unsigned char *) src;
int i;
for (i = 0; i < rows; i++) { for (i = 0; i < rows; i++) {
oil_memcpy (pDest, pSrc, count); oil_memcpy (dest, src, count);
pSrc += src_pitch; src += src_pitch;
pDest += dst_pitch; dest += dst_pitch;
} }
return 0;
} }
#define USE_FOR_DSCALER #define USE_FOR_DSCALER
@ -119,9 +111,9 @@ G_DEFINE_TYPE (GstDeinterlaceMethodTomsMoComp,
enum enum
{ {
ARG_0, PROP_0,
ARG_SEARCH_EFFORT, PROP_SEARCH_EFFORT,
ARG_STRANGE_BOB PROP_STRANGE_BOB
}; };
static void static void
@ -132,10 +124,10 @@ gst_deinterlace_method_tomsmocomp_set_property (GObject * object, guint prop_id,
GST_DEINTERLACE_METHOD_TOMSMOCOMP (object); GST_DEINTERLACE_METHOD_TOMSMOCOMP (object);
switch (prop_id) { switch (prop_id) {
case ARG_SEARCH_EFFORT: case PROP_SEARCH_EFFORT:
self->search_effort = g_value_get_uint (value); self->search_effort = g_value_get_uint (value);
break; break;
case ARG_STRANGE_BOB: case PROP_STRANGE_BOB:
self->strange_bob = g_value_get_boolean (value); self->strange_bob = g_value_get_boolean (value);
break; break;
default: default:
@ -151,10 +143,10 @@ gst_deinterlace_method_tomsmocomp_get_property (GObject * object, guint prop_id,
GST_DEINTERLACE_METHOD_TOMSMOCOMP (object); GST_DEINTERLACE_METHOD_TOMSMOCOMP (object);
switch (prop_id) { switch (prop_id) {
case ARG_SEARCH_EFFORT: case PROP_SEARCH_EFFORT:
g_value_set_uint (value, self->search_effort); g_value_set_uint (value, self->search_effort);
break; break;
case ARG_STRANGE_BOB: case PROP_STRANGE_BOB:
g_value_set_boolean (value, self->strange_bob); g_value_set_boolean (value, self->strange_bob);
break; break;
default: default:
@ -175,13 +167,13 @@ static void
gobject_class->set_property = gst_deinterlace_method_tomsmocomp_set_property; gobject_class->set_property = gst_deinterlace_method_tomsmocomp_set_property;
gobject_class->get_property = gst_deinterlace_method_tomsmocomp_get_property; gobject_class->get_property = gst_deinterlace_method_tomsmocomp_get_property;
g_object_class_install_property (gobject_class, ARG_SEARCH_EFFORT, g_object_class_install_property (gobject_class, PROP_SEARCH_EFFORT,
g_param_spec_uint ("search-effort", g_param_spec_uint ("search-effort",
"Search Effort", "Search Effort",
"Search Effort", 0, 27, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) "Search Effort", 0, 27, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
); );
g_object_class_install_property (gobject_class, ARG_STRANGE_BOB, g_object_class_install_property (gobject_class, PROP_STRANGE_BOB,
g_param_spec_boolean ("strange-bob", g_param_spec_boolean ("strange-bob",
"Strange Bob", "Strange Bob",
"Use strange bob", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) "Use strange bob", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
@ -194,16 +186,21 @@ static void
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) { if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
dim_class->deinterlace_frame = tomsmocompDScaler_MMXEXT; dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_MMXEXT;
dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_MMXEXT;
} else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) { } else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) {
dim_class->deinterlace_frame = tomsmocompDScaler_3DNOW; dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_3DNOW;
dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_3DNOW;
} else if (cpu_flags & OIL_IMPL_FLAG_MMX) { } else if (cpu_flags & OIL_IMPL_FLAG_MMX) {
dim_class->deinterlace_frame = tomsmocompDScaler_MMX; dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_MMX;
dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_MMX;
} else { } else {
dim_class->deinterlace_frame = tomsmocompDScaler_C; dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_C;
dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_C;
} }
#else #else
dim_class->deinterlace_frame = tomsmocompDScaler_C; dim_class->deinterlace_frame_yuy2 = tomsmocompDScaler_C;
dim_class->deinterlace_frame_yvyu = tomsmocompDScaler_C;
#endif #endif
} }

View file

@ -61,36 +61,44 @@
#define SEFUNC(x) Search_Effort_C_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight) #define SEFUNC(x) Search_Effort_C_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
#endif #endif
static void FUNCT_NAME(GstDeinterlaceMethod *d_method, GstDeinterlace* object, GstBuffer *outbuf) static void FUNCT_NAME(GstDeinterlaceMethod *d_method, const GstDeinterlaceField* history, guint history_count, GstBuffer *outbuf)
{ {
GstDeinterlaceMethodTomsMoComp *self = GST_DEINTERLACE_METHOD_TOMSMOCOMP (d_method); GstDeinterlaceMethodTomsMoComp *self = GST_DEINTERLACE_METHOD_TOMSMOCOMP (d_method);
long SearchEffort = self->search_effort; glong SearchEffort = self->search_effort;
int UseStrangeBob = self->strange_bob; gint UseStrangeBob = self->strange_bob;
int IsOdd; gint IsOdd;
const unsigned char *pWeaveSrc; const guint8 *pWeaveSrc;
const unsigned char *pWeaveSrcP; const guint8 *pWeaveSrcP;
unsigned char *pWeaveDest; guint8 *pWeaveDest;
const unsigned char *pCopySrc; const guint8 *pCopySrc;
const unsigned char *pCopySrcP; const guint8 *pCopySrcP;
unsigned char *pCopyDest; guint8 *pCopyDest;
int src_pitch; gint src_pitch;
int dst_pitch; gint dst_pitch;
int rowsize; gint rowsize;
int FldHeight; gint FldHeight;
/* double stride do address just every odd/even scanline */ /* double stride do address just every odd/even scanline */
src_pitch = object->field_stride; src_pitch = self->parent.row_stride[0]*2;
dst_pitch = object->row_stride; dst_pitch = self->parent.row_stride[0];
rowsize = object->row_stride; rowsize = self->parent.row_stride[0];
FldHeight = object->field_height; FldHeight = self->parent.frame_height / 2;
pCopySrc = GST_BUFFER_DATA(object->field_history[object->history_count-1].buf); pCopySrc = GST_BUFFER_DATA(history[history_count-1].buf);
pCopySrcP = GST_BUFFER_DATA(object->field_history[object->history_count-3].buf); if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
pWeaveSrc = GST_BUFFER_DATA(object->field_history[object->history_count-2].buf); pCopySrc += rowsize;
pWeaveSrcP = GST_BUFFER_DATA(object->field_history[object->history_count-4].buf); pCopySrcP = GST_BUFFER_DATA(history[history_count-3].buf);
if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
pCopySrcP += rowsize;
pWeaveSrc = GST_BUFFER_DATA(history[history_count-2].buf);
if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
pWeaveSrc += rowsize;
pWeaveSrcP = GST_BUFFER_DATA(history[history_count-4].buf);
if (history[history_count - 4].flags & PICTURE_INTERLACED_BOTTOM)
pWeaveSrcP += rowsize;
/* use bottom field and interlace top field */ /* use bottom field and interlace top field */
if (object->field_history[object->history_count-2].flags == PICTURE_INTERLACED_BOTTOM) { if (history[history_count-2].flags == PICTURE_INTERLACED_BOTTOM) {
IsOdd = 1; IsOdd = 1;
// if we have an odd field we copy an even field and weave an odd field // if we have an odd field we copy an even field and weave an odd field

View file

@ -3,7 +3,7 @@
* GStreamer * GStreamer
* Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net> * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard. * Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
* Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <slomo@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -33,7 +33,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -62,16 +61,10 @@ typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodVFIRClass;
* C implementation. * C implementation.
*/ */
static inline void static inline void
deinterlace_line_c (GstDeinterlaceMethod * self, GstDeinterlace * parent, deinterlace_c (guint8 * dst, const guint8 * lum_m4, const guint8 * lum_m3,
guint8 * dst, GstDeinterlaceScanlineData * scanlines, gint width) const guint8 * lum_m2, const guint8 * lum_m1, const guint8 * lum, gint size)
{ {
gint sum; gint sum;
guint8 *lum_m4 = scanlines->tt1;
guint8 *lum_m3 = scanlines->t0;
guint8 *lum_m2 = scanlines->m1;
guint8 *lum_m1 = scanlines->b0;
guint8 *lum = scanlines->bb1;
gint size = width * 2;
for (; size >= 0; size--) { for (; size >= 0; size--) {
sum = -lum_m4[0]; sum = -lum_m4[0];
@ -89,18 +82,27 @@ deinterlace_line_c (GstDeinterlaceMethod * self, GstDeinterlace * parent,
} }
} }
static void
deinterlace_line_packed_c (GstDeinterlaceSimpleMethod * self, guint8 * dst,
const GstDeinterlaceScanlineData * scanlines)
{
const guint8 *lum_m4 = scanlines->tt1;
const guint8 *lum_m3 = scanlines->t0;
const guint8 *lum_m2 = scanlines->m1;
const guint8 *lum_m1 = scanlines->b0;
const guint8 *lum = scanlines->bb1;
gint size = self->parent.row_stride[0];
deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
}
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
#include "mmx.h" #include "mmx.h"
static void static void
deinterlace_line_mmx (GstDeinterlaceMethod * self, GstDeinterlace * parent, deinterlace_mmx (guint8 * dst, const guint8 * lum_m4, const guint8 * lum_m3,
guint8 * dst, GstDeinterlaceScanlineData * scanlines, gint width) const guint8 * lum_m2, const guint8 * lum_m1, const guint8 * lum, gint size)
{ {
mmx_t rounder; mmx_t rounder;
guint8 *lum_m4 = scanlines->tt1;
guint8 *lum_m3 = scanlines->t0;
guint8 *lum_m2 = scanlines->m1;
guint8 *lum_m1 = scanlines->b0;
guint8 *lum = scanlines->bb1;
rounder.uw[0] = 4; rounder.uw[0] = 4;
rounder.uw[1] = 4; rounder.uw[1] = 4;
@ -109,7 +111,7 @@ deinterlace_line_mmx (GstDeinterlaceMethod * self, GstDeinterlace * parent,
pxor_r2r (mm7, mm7); pxor_r2r (mm7, mm7);
movq_m2r (rounder, mm6); movq_m2r (rounder, mm6);
for (; width > 1; width -= 2) { for (; size > 3; size -= 4) {
movd_m2r (*lum_m4, mm0); movd_m2r (*lum_m4, mm0);
movd_m2r (*lum_m3, mm1); movd_m2r (*lum_m3, mm1);
movd_m2r (*lum_m2, mm2); movd_m2r (*lum_m2, mm2);
@ -140,15 +142,22 @@ deinterlace_line_mmx (GstDeinterlaceMethod * self, GstDeinterlace * parent,
emms (); emms ();
/* Handle odd widths */ /* Handle odd widths */
if (width > 0) { if (size > 0)
scanlines->tt1 = lum_m4; deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
scanlines->t0 = lum_m3; }
scanlines->m1 = lum_m2;
scanlines->b0 = lum_m1;
scanlines->bb1 = lum;
deinterlace_line_c (self, parent, dst, scanlines, width); static void
} deinterlace_line_packed_mmx (GstDeinterlaceSimpleMethod * self, guint8 * dst,
const GstDeinterlaceScanlineData * scanlines)
{
const guint8 *lum_m4 = scanlines->tt1;
const guint8 *lum_m3 = scanlines->t0;
const guint8 *lum_m2 = scanlines->m1;
const guint8 *lum_m1 = scanlines->b0;
const guint8 *lum = scanlines->bb1;
gint size = self->parent.row_stride[0];
deinterlace_mmx (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
} }
#endif #endif
@ -172,12 +181,15 @@ gst_deinterlace_method_vfir_class_init (GstDeinterlaceMethodVFIRClass * klass)
#ifdef BUILD_X86_ASM #ifdef BUILD_X86_ASM
if (cpu_flags & OIL_IMPL_FLAG_MMX) { if (cpu_flags & OIL_IMPL_FLAG_MMX) {
dism_class->interpolate_scanline = deinterlace_line_mmx; dism_class->interpolate_scanline_yuy2 = deinterlace_line_packed_mmx;
dism_class->interpolate_scanline_yvyu = deinterlace_line_packed_mmx;
} else { } else {
dism_class->interpolate_scanline = deinterlace_line_c; dism_class->interpolate_scanline_yuy2 = deinterlace_line_packed_c;
dism_class->interpolate_scanline_yvyu = deinterlace_line_packed_c;
} }
#else #else
dism_class->interpolate_scanline = deinterlace_line_c; dism_class->interpolate_scanline_yuy2 = deinterlace_line_packed_c;
dism_class->interpolate_scanline_yvyu = deinterlace_line_packed_c;
#endif #endif
} }

View file

@ -1,7 +1,7 @@
/** /**
* Weave frames * Weave frames
* Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>. * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -28,7 +28,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -43,23 +42,20 @@
GType gst_deinterlace_method_weave_get_type (void); GType gst_deinterlace_method_weave_get_type (void);
typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeave; typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeave;
typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveClass; typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveClass;
static void static void
deinterlace_scanline_weave (GstDeinterlaceMethod * self, deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
oil_memcpy (out, scanlines->m1, parent->row_stride); oil_memcpy (out, scanlines->m1, self->parent.row_stride[0]);
} }
static void static void
copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace * parent, copy_scanline_packed (GstDeinterlaceSimpleMethod * self, guint8 * out,
guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width) const GstDeinterlaceScanlineData * scanlines)
{ {
oil_memcpy (out, scanlines->m0, parent->row_stride); oil_memcpy (out, scanlines->m0, self->parent.row_stride[0]);
} }
G_DEFINE_TYPE (GstDeinterlaceMethodWeave, gst_deinterlace_method_weave, G_DEFINE_TYPE (GstDeinterlaceMethodWeave, gst_deinterlace_method_weave,
@ -77,8 +73,9 @@ gst_deinterlace_method_weave_class_init (GstDeinterlaceMethodWeaveClass * klass)
dim_class->nick = "weave"; dim_class->nick = "weave";
dim_class->latency = 0; dim_class->latency = 0;
dism_class->interpolate_scanline = deinterlace_scanline_weave; dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;
dism_class->copy_scanline = copy_scanline; dism_class->interpolate_scanline_yvyu = deinterlace_scanline_weave_packed;
dism_class->copy_scanline_yvyu = copy_scanline_packed;
} }
static void static void

View file

@ -1,7 +1,7 @@
/** /**
* Weave frames, bottom-field-first. * Weave frames, bottom-field-first.
* Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>. * Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>.
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -28,7 +28,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -43,27 +42,24 @@
GType gst_deinterlace_method_weave_bff_get_type (void); GType gst_deinterlace_method_weave_bff_get_type (void);
typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveBFF; typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveBFF;
typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveBFFClass; typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveBFFClass;
static void static void
deinterlace_scanline_weave (GstDeinterlaceMethod * self, deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
oil_memcpy (out, scanlines->m1, parent->row_stride); oil_memcpy (out, scanlines->m1, self->parent.row_stride[0]);
} }
static void static void
copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace * parent, copy_scanline_packed (GstDeinterlaceSimpleMethod * self, guint8 * out,
guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width) const GstDeinterlaceScanlineData * scanlines)
{ {
/* FIXME: original code used m2 and m0 but this looks really bad */ /* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) { if (scanlines->bottom_field) {
oil_memcpy (out, scanlines->bb2, parent->row_stride); oil_memcpy (out, scanlines->bb2, self->parent.row_stride[0]);
} else { } else {
oil_memcpy (out, scanlines->bb0, parent->row_stride); oil_memcpy (out, scanlines->bb0, self->parent.row_stride[0]);
} }
} }
@ -83,8 +79,10 @@ gst_deinterlace_method_weave_bff_class_init (GstDeinterlaceMethodWeaveBFFClass *
dim_class->nick = "weavebff"; dim_class->nick = "weavebff";
dim_class->latency = 0; dim_class->latency = 0;
dism_class->interpolate_scanline = deinterlace_scanline_weave; dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;
dism_class->copy_scanline = copy_scanline; dism_class->interpolate_scanline_yvyu = deinterlace_scanline_weave_packed;
dism_class->copy_scanline_yuy2 = copy_scanline_packed;
dism_class->copy_scanline_yvyu = copy_scanline_packed;
} }
static void static void

View file

@ -1,7 +1,7 @@
/** /**
* Weave frames, top-field-first. * Weave frames, top-field-first.
* Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>. * Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>.
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk> * Copyright (C) 2008,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -29,7 +29,6 @@
# include "config.h" # include "config.h"
#endif #endif
#include "_stdint.h"
#include "gstdeinterlace.h" #include "gstdeinterlace.h"
#include <string.h> #include <string.h>
@ -44,27 +43,24 @@
GType gst_deinterlace_method_weave_tff_get_type (void); GType gst_deinterlace_method_weave_tff_get_type (void);
typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveTFF; typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveTFF;
typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveTFFClass; typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveTFFClass;
static void static void
deinterlace_scanline_weave (GstDeinterlaceMethod * self, deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
GstDeinterlace * parent, guint8 * out, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
GstDeinterlaceScanlineData * scanlines, gint width)
{ {
oil_memcpy (out, scanlines->m1, parent->row_stride); oil_memcpy (out, scanlines->m1, self->parent.row_stride[0]);
} }
static void static void
copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace * parent, copy_scanline_packed (GstDeinterlaceSimpleMethod * self,
guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width) guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{ {
/* FIXME: original code used m2 and m0 but this looks really bad */ /* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) { if (scanlines->bottom_field) {
oil_memcpy (out, scanlines->bb0, parent->row_stride); oil_memcpy (out, scanlines->bb0, self->parent.row_stride[0]);
} else { } else {
oil_memcpy (out, scanlines->bb2, parent->row_stride); oil_memcpy (out, scanlines->bb2, self->parent.row_stride[0]);
} }
} }
@ -84,8 +80,10 @@ gst_deinterlace_method_weave_tff_class_init (GstDeinterlaceMethodWeaveTFFClass *
dim_class->nick = "weavetff"; dim_class->nick = "weavetff";
dim_class->latency = 0; dim_class->latency = 0;
dism_class->interpolate_scanline = deinterlace_scanline_weave; dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;
dism_class->copy_scanline = copy_scanline; dism_class->interpolate_scanline_yvyu = deinterlace_scanline_weave_packed;
dism_class->copy_scanline_yuy2 = copy_scanline_packed;
dism_class->copy_scanline_yvyu = copy_scanline_packed;
} }
static void static void