mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
deinterlace: Move deinterlacing methods to their own file
This commit is contained in:
parent
a405d5a4f1
commit
600f82fbfe
15 changed files with 581 additions and 513 deletions
|
@ -2,6 +2,7 @@ plugin_LTLIBRARIES = libgstdeinterlace.la
|
||||||
|
|
||||||
libgstdeinterlace_la_SOURCES = \
|
libgstdeinterlace_la_SOURCES = \
|
||||||
gstdeinterlace.c \
|
gstdeinterlace.c \
|
||||||
|
gstdeinterlacemethod.c \
|
||||||
tvtime/tomsmocomp.c \
|
tvtime/tomsmocomp.c \
|
||||||
tvtime/greedy.c \
|
tvtime/greedy.c \
|
||||||
tvtime/greedyh.c \
|
tvtime/greedyh.c \
|
||||||
|
@ -22,6 +23,7 @@ libgstdeinterlace_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
gstdeinterlace.h \
|
gstdeinterlace.h \
|
||||||
|
gstdeinterlacemethod.h \
|
||||||
tvtime/mmx.h \
|
tvtime/mmx.h \
|
||||||
tvtime/sse.h \
|
tvtime/sse.h \
|
||||||
tvtime/greedyh.asm \
|
tvtime/greedyh.asm \
|
||||||
|
|
|
@ -45,12 +45,6 @@
|
||||||
GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
|
GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
|
||||||
#define GST_CAT_DEFAULT (deinterlace_debug)
|
#define GST_CAT_DEFAULT (deinterlace_debug)
|
||||||
|
|
||||||
/* Object signals and args */
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Properties */
|
/* Properties */
|
||||||
|
|
||||||
#define DEFAULT_MODE GST_DEINTERLACE_MODE_INTERLACED
|
#define DEFAULT_MODE GST_DEINTERLACE_MODE_INTERLACED
|
||||||
|
@ -68,365 +62,6 @@ enum
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
|
||||||
gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass)
|
|
||||||
{
|
|
||||||
klass->setup = gst_deinterlace_method_setup_impl;
|
|
||||||
klass->supported = gst_deinterlace_method_supported_impl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_deinterlace_method_init (GstDeinterlaceMethod * self)
|
|
||||||
{
|
|
||||||
self->format = GST_VIDEO_FORMAT_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
|
|
||||||
const GstDeinterlaceField * history, guint history_count,
|
|
||||||
GstBuffer * outbuf)
|
|
||||||
{
|
|
||||||
g_assert (self->deinterlace_frame != NULL);
|
|
||||||
self->deinterlace_frame (self, history, history_count, outbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self)
|
|
||||||
{
|
|
||||||
GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
|
|
||||||
|
|
||||||
return klass->fields_required;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self)
|
|
||||||
{
|
|
||||||
GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
|
|
||||||
|
|
||||||
return klass->latency;
|
|
||||||
}
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method,
|
|
||||||
GST_TYPE_DEINTERLACE_METHOD);
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_deinterlace_simple_method_supported (GstDeinterlaceMethodClass * mklass,
|
|
||||||
GstVideoFormat format, gint width, gint height)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
gst_deinterlace_simple_method_interpolate_scanline_packed
|
|
||||||
(GstDeinterlaceSimpleMethod * self, guint8 * out,
|
|
||||||
const GstDeinterlaceScanlineData * scanlines)
|
|
||||||
{
|
|
||||||
oil_memcpy (out, scanlines->m1, self->parent.row_stride[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod *
|
|
||||||
self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
|
|
||||||
{
|
|
||||||
oil_memcpy (out, scanlines->m0, self->parent.row_stride[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
GstDeinterlaceScanlineData scanlines;
|
|
||||||
guint8 *out = GST_BUFFER_DATA (outbuf);
|
|
||||||
guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL;
|
|
||||||
gint cur_field_idx = history_count - dm_class->fields_required;
|
|
||||||
guint cur_field_flags = history[cur_field_idx].flags;
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (dm_class->fields_required >= 2) {
|
|
||||||
field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf);
|
|
||||||
if (history[cur_field_idx + 1].flags & PICTURE_INTERLACED_BOTTOM)
|
|
||||||
field1 += row_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
/* double the first scanline of the bottom field */
|
|
||||||
oil_memcpy (out, field0, row_stride);
|
|
||||||
out += row_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
oil_memcpy (out, field0, row_stride);
|
|
||||||
out += row_stride;
|
|
||||||
|
|
||||||
for (line = 2; line <= field_height; line++) {
|
|
||||||
|
|
||||||
memset (&scanlines, 0, sizeof (scanlines));
|
|
||||||
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
|
|
||||||
|
|
||||||
/* interp. scanline */
|
|
||||||
scanlines.t0 = field0;
|
|
||||||
scanlines.b0 = field0 + field_stride;
|
|
||||||
|
|
||||||
if (field1 != NULL) {
|
|
||||||
scanlines.tt1 = field1;
|
|
||||||
scanlines.m1 = field1 + field_stride;
|
|
||||||
scanlines.bb1 = field1 + field_stride * 2;
|
|
||||||
field1 += field_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field2 != NULL) {
|
|
||||||
scanlines.t2 = field2;
|
|
||||||
scanlines.b2 = field2 + field_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field3 != NULL) {
|
|
||||||
scanlines.tt3 = field3;
|
|
||||||
scanlines.m3 = field3 + field_stride;
|
|
||||||
scanlines.bb3 = field3 + field_stride * 2;
|
|
||||||
field3 += field_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set valid data for corner cases */
|
|
||||||
if (line == 2) {
|
|
||||||
scanlines.tt1 = scanlines.bb1;
|
|
||||||
scanlines.tt3 = scanlines.bb3;
|
|
||||||
} else if (line == field_height) {
|
|
||||||
scanlines.bb1 = scanlines.tt1;
|
|
||||||
scanlines.bb3 = scanlines.tt3;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->interpolate_scanline_packed (self, out, &scanlines);
|
|
||||||
out += row_stride;
|
|
||||||
|
|
||||||
memset (&scanlines, 0, sizeof (scanlines));
|
|
||||||
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
|
|
||||||
|
|
||||||
/* copy a scanline */
|
|
||||||
scanlines.tt0 = field0;
|
|
||||||
scanlines.m0 = field0 + field_stride;
|
|
||||||
scanlines.bb0 = field0 + field_stride * 2;
|
|
||||||
field0 += field_stride;
|
|
||||||
|
|
||||||
if (field1 != NULL) {
|
|
||||||
scanlines.t1 = field1;
|
|
||||||
scanlines.b1 = field1 + field_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field2 != NULL) {
|
|
||||||
scanlines.tt2 = field2;
|
|
||||||
scanlines.m2 = field2 + field_stride;
|
|
||||||
scanlines.bb2 = field2 + field_stride * 2;
|
|
||||||
field2 += field_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field3 != NULL) {
|
|
||||||
scanlines.t3 = field3;
|
|
||||||
scanlines.b3 = field3 + field_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set valid data for corner cases */
|
|
||||||
if (line == field_height) {
|
|
||||||
scanlines.bb0 = scanlines.tt0;
|
|
||||||
scanlines.b1 = scanlines.t1;
|
|
||||||
scanlines.bb2 = scanlines.tt2;
|
|
||||||
scanlines.b3 = scanlines.t3;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->copy_scanline_packed (self, out, &scanlines);
|
|
||||||
out += row_stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur_field_flags == PICTURE_INTERLACED_TOP) {
|
|
||||||
/* double the last scanline of the top field */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass *
|
|
||||||
klass)
|
|
||||||
{
|
|
||||||
GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
|
|
||||||
|
|
||||||
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->setup = gst_deinterlace_simple_method_setup;
|
|
||||||
dm_class->supported = gst_deinterlace_simple_method_supported;
|
|
||||||
|
|
||||||
klass->interpolate_scanline_yuy2 =
|
|
||||||
gst_deinterlace_simple_method_interpolate_scanline_packed;
|
|
||||||
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
|
|
||||||
gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
|
||||||
static GType
|
static GType
|
||||||
gst_deinterlace_methods_get_type (void)
|
gst_deinterlace_methods_get_type (void)
|
||||||
|
|
|
@ -29,11 +29,7 @@
|
||||||
#include <liboil/liboilcpu.h>
|
#include <liboil/liboilcpu.h>
|
||||||
#include <liboil/liboilfunction.h>
|
#include <liboil/liboilfunction.h>
|
||||||
|
|
||||||
#ifdef HAVE_GCC_ASM
|
#include "gstdeinterlacemethod.h"
|
||||||
#if defined(HAVE_CPU_I386) || defined(HAVE_CPU_X86_64)
|
|
||||||
#define BUILD_X86_ASM
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -51,139 +47,6 @@ G_BEGIN_DECLS
|
||||||
typedef struct _GstDeinterlace GstDeinterlace;
|
typedef struct _GstDeinterlace GstDeinterlace;
|
||||||
typedef struct _GstDeinterlaceClass GstDeinterlaceClass;
|
typedef struct _GstDeinterlaceClass GstDeinterlaceClass;
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD (gst_deinterlace_method_get_type ())
|
|
||||||
#define GST_IS_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD))
|
|
||||||
#define GST_IS_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD))
|
|
||||||
#define GST_DEINTERLACE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
|
|
||||||
#define GST_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethod))
|
|
||||||
#define GST_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
|
|
||||||
#define GST_DEINTERLACE_METHOD_CAST(obj) ((GstDeinterlaceMethod*)(obj))
|
|
||||||
|
|
||||||
typedef struct _GstDeinterlaceMethod GstDeinterlaceMethod;
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (*GstDeinterlaceMethodDeinterlaceFunction) (GstDeinterlaceMethod *self, const GstDeinterlaceField *history, guint history_count, GstBuffer *outbuf);
|
|
||||||
|
|
||||||
struct _GstDeinterlaceMethod {
|
|
||||||
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 {
|
|
||||||
GstObjectClass parent_class;
|
|
||||||
guint fields_required;
|
|
||||||
guint latency;
|
|
||||||
|
|
||||||
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 *nick;
|
|
||||||
};
|
|
||||||
|
|
||||||
GType gst_deinterlace_method_get_type (void);
|
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_SIMPLE_METHOD (gst_deinterlace_simple_method_get_type ())
|
|
||||||
#define GST_IS_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
|
|
||||||
#define GST_IS_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
|
|
||||||
#define GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
|
|
||||||
#define GST_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethod))
|
|
||||||
#define GST_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
|
|
||||||
#define GST_DEINTERLACE_SIMPLE_METHOD_CAST(obj) ((GstDeinterlaceSimpleMethod*)(obj))
|
|
||||||
|
|
||||||
typedef struct _GstDeinterlaceSimpleMethod GstDeinterlaceSimpleMethod;
|
|
||||||
typedef struct _GstDeinterlaceSimpleMethodClass GstDeinterlaceSimpleMethodClass;
|
|
||||||
typedef struct _GstDeinterlaceScanlineData GstDeinterlaceScanlineData;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This structure defines the simple deinterlacer plugin.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct _GstDeinterlaceScanlineData {
|
|
||||||
const guint8 *tt0, *t0, *m0, *b0, *bb0;
|
|
||||||
const guint8 *tt1, *t1, *m1, *b1, *bb1;
|
|
||||||
const guint8 *tt2, *t2, *m2, *b2, *bb2;
|
|
||||||
const guint8 *tt3, *t3, *m3, *b3, *bb3;
|
|
||||||
gboolean bottom_field;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For interpolate_scanline the input is:
|
|
||||||
*
|
|
||||||
* | t-3 t-2 t-1 t
|
|
||||||
* | Field 3 | Field 2 | Field 1 | Field 0 |
|
|
||||||
* | TT3 | | TT1 | |
|
|
||||||
* | | T2 | | T0 |
|
|
||||||
* | M3 | | M1 | |
|
|
||||||
* | | B2 | | B0 |
|
|
||||||
* | BB3 | | BB1 | |
|
|
||||||
*
|
|
||||||
* For copy_scanline the input is:
|
|
||||||
*
|
|
||||||
* | t-3 t-2 t-1 t
|
|
||||||
* | Field 3 | Field 2 | Field 1 | Field 0 |
|
|
||||||
* | | TT2 | | TT0 |
|
|
||||||
* | T3 | | T1 | |
|
|
||||||
* | | M2 | | M0 |
|
|
||||||
* | B3 | | B1 | |
|
|
||||||
* | | BB2 | | BB0 |
|
|
||||||
*
|
|
||||||
* All other values are NULL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef void (*GstDeinterlaceSimpleMethodPackedFunction) (GstDeinterlaceSimpleMethod *self, guint8 *out, const GstDeinterlaceScanlineData *scanlines);
|
|
||||||
|
|
||||||
struct _GstDeinterlaceSimpleMethod {
|
|
||||||
GstDeinterlaceMethod parent;
|
|
||||||
|
|
||||||
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_packed;
|
|
||||||
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_packed;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _GstDeinterlaceSimpleMethodClass {
|
|
||||||
GstDeinterlaceMethodClass parent_class;
|
|
||||||
|
|
||||||
/* Packed formats */
|
|
||||||
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_yuy2;
|
|
||||||
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_yuy2;
|
|
||||||
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_yvyu;
|
|
||||||
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_yvyu;
|
|
||||||
};
|
|
||||||
|
|
||||||
GType gst_deinterlace_simple_method_get_type (void);
|
|
||||||
|
|
||||||
#define GST_DEINTERLACE_MAX_FIELD_HISTORY 10
|
#define GST_DEINTERLACE_MAX_FIELD_HISTORY 10
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
|
389
gst/deinterlace/gstdeinterlacemethod.c
Normal file
389
gst/deinterlace/gstdeinterlacemethod.c
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
* GStreamer
|
||||||
|
* Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <liboil/liboil.h>
|
||||||
|
#include <liboil/liboilfunction.h>
|
||||||
|
|
||||||
|
#include "gstdeinterlacemethod.h"
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (GstDeinterlaceMethod, gst_deinterlace_method, GST_TYPE_OBJECT);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass)
|
||||||
|
{
|
||||||
|
klass->setup = gst_deinterlace_method_setup_impl;
|
||||||
|
klass->supported = gst_deinterlace_method_supported_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_deinterlace_method_init (GstDeinterlaceMethod * self)
|
||||||
|
{
|
||||||
|
self->format = GST_VIDEO_FORMAT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
|
||||||
|
const GstDeinterlaceField * history, guint history_count,
|
||||||
|
GstBuffer * outbuf)
|
||||||
|
{
|
||||||
|
g_assert (self->deinterlace_frame != NULL);
|
||||||
|
self->deinterlace_frame (self, history, history_count, outbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
gint
|
||||||
|
gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self)
|
||||||
|
{
|
||||||
|
GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
|
||||||
|
|
||||||
|
return klass->fields_required;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint
|
||||||
|
gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self)
|
||||||
|
{
|
||||||
|
GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
|
||||||
|
|
||||||
|
return klass->latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method,
|
||||||
|
GST_TYPE_DEINTERLACE_METHOD);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_deinterlace_simple_method_supported (GstDeinterlaceMethodClass * mklass,
|
||||||
|
GstVideoFormat format, gint width, gint height)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
gst_deinterlace_simple_method_interpolate_scanline_packed
|
||||||
|
(GstDeinterlaceSimpleMethod * self, guint8 * out,
|
||||||
|
const GstDeinterlaceScanlineData * scanlines)
|
||||||
|
{
|
||||||
|
oil_memcpy (out, scanlines->m1, self->parent.row_stride[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod *
|
||||||
|
self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
|
||||||
|
{
|
||||||
|
oil_memcpy (out, scanlines->m0, self->parent.row_stride[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
GstDeinterlaceScanlineData scanlines;
|
||||||
|
guint8 *out = GST_BUFFER_DATA (outbuf);
|
||||||
|
guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL;
|
||||||
|
gint cur_field_idx = history_count - dm_class->fields_required;
|
||||||
|
guint cur_field_flags = history[cur_field_idx].flags;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (dm_class->fields_required >= 2) {
|
||||||
|
field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf);
|
||||||
|
if (history[cur_field_idx + 1].flags & PICTURE_INTERLACED_BOTTOM)
|
||||||
|
field1 += row_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
/* double the first scanline of the bottom field */
|
||||||
|
oil_memcpy (out, field0, row_stride);
|
||||||
|
out += row_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
oil_memcpy (out, field0, row_stride);
|
||||||
|
out += row_stride;
|
||||||
|
|
||||||
|
for (line = 2; line <= field_height; line++) {
|
||||||
|
|
||||||
|
memset (&scanlines, 0, sizeof (scanlines));
|
||||||
|
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
|
||||||
|
|
||||||
|
/* interp. scanline */
|
||||||
|
scanlines.t0 = field0;
|
||||||
|
scanlines.b0 = field0 + field_stride;
|
||||||
|
|
||||||
|
if (field1 != NULL) {
|
||||||
|
scanlines.tt1 = field1;
|
||||||
|
scanlines.m1 = field1 + field_stride;
|
||||||
|
scanlines.bb1 = field1 + field_stride * 2;
|
||||||
|
field1 += field_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field2 != NULL) {
|
||||||
|
scanlines.t2 = field2;
|
||||||
|
scanlines.b2 = field2 + field_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field3 != NULL) {
|
||||||
|
scanlines.tt3 = field3;
|
||||||
|
scanlines.m3 = field3 + field_stride;
|
||||||
|
scanlines.bb3 = field3 + field_stride * 2;
|
||||||
|
field3 += field_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set valid data for corner cases */
|
||||||
|
if (line == 2) {
|
||||||
|
scanlines.tt1 = scanlines.bb1;
|
||||||
|
scanlines.tt3 = scanlines.bb3;
|
||||||
|
} else if (line == field_height) {
|
||||||
|
scanlines.bb1 = scanlines.tt1;
|
||||||
|
scanlines.bb3 = scanlines.tt3;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->interpolate_scanline_packed (self, out, &scanlines);
|
||||||
|
out += row_stride;
|
||||||
|
|
||||||
|
memset (&scanlines, 0, sizeof (scanlines));
|
||||||
|
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
|
||||||
|
|
||||||
|
/* copy a scanline */
|
||||||
|
scanlines.tt0 = field0;
|
||||||
|
scanlines.m0 = field0 + field_stride;
|
||||||
|
scanlines.bb0 = field0 + field_stride * 2;
|
||||||
|
field0 += field_stride;
|
||||||
|
|
||||||
|
if (field1 != NULL) {
|
||||||
|
scanlines.t1 = field1;
|
||||||
|
scanlines.b1 = field1 + field_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field2 != NULL) {
|
||||||
|
scanlines.tt2 = field2;
|
||||||
|
scanlines.m2 = field2 + field_stride;
|
||||||
|
scanlines.bb2 = field2 + field_stride * 2;
|
||||||
|
field2 += field_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field3 != NULL) {
|
||||||
|
scanlines.t3 = field3;
|
||||||
|
scanlines.b3 = field3 + field_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set valid data for corner cases */
|
||||||
|
if (line == field_height) {
|
||||||
|
scanlines.bb0 = scanlines.tt0;
|
||||||
|
scanlines.b1 = scanlines.t1;
|
||||||
|
scanlines.bb2 = scanlines.tt2;
|
||||||
|
scanlines.b3 = scanlines.t3;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->copy_scanline_packed (self, out, &scanlines);
|
||||||
|
out += row_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_field_flags == PICTURE_INTERLACED_TOP) {
|
||||||
|
/* double the last scanline of the top field */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass *
|
||||||
|
klass)
|
||||||
|
{
|
||||||
|
GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
|
||||||
|
|
||||||
|
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->setup = gst_deinterlace_simple_method_setup;
|
||||||
|
dm_class->supported = gst_deinterlace_simple_method_supported;
|
||||||
|
|
||||||
|
klass->interpolate_scanline_yuy2 =
|
||||||
|
gst_deinterlace_simple_method_interpolate_scanline_packed;
|
||||||
|
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
|
||||||
|
gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
|
||||||
|
{
|
||||||
|
}
|
179
gst/deinterlace/gstdeinterlacemethod.h
Normal file
179
gst/deinterlace/gstdeinterlacemethod.h
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* GStreamer
|
||||||
|
* Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GST_DEINTERLACE_METHOD_H__
|
||||||
|
#define __GST_DEINTERLACE_METHOD_H__
|
||||||
|
|
||||||
|
#include <liboil/liboil.h>
|
||||||
|
#include <liboil/liboilcpu.h>
|
||||||
|
#include <liboil/liboilfunction.h>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_GCC_ASM
|
||||||
|
#if defined(HAVE_CPU_I386) || defined(HAVE_CPU_X86_64)
|
||||||
|
#define BUILD_X86_ASM
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GST_TYPE_DEINTERLACE_METHOD (gst_deinterlace_method_get_type ())
|
||||||
|
#define GST_IS_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD))
|
||||||
|
#define GST_IS_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD))
|
||||||
|
#define GST_DEINTERLACE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
|
||||||
|
#define GST_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethod))
|
||||||
|
#define GST_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
|
||||||
|
#define GST_DEINTERLACE_METHOD_CAST(obj) ((GstDeinterlaceMethod*)(obj))
|
||||||
|
|
||||||
|
typedef struct _GstDeinterlaceMethod GstDeinterlaceMethod;
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef void (*GstDeinterlaceMethodDeinterlaceFunction) (GstDeinterlaceMethod *self, const GstDeinterlaceField *history, guint history_count, GstBuffer *outbuf);
|
||||||
|
|
||||||
|
struct _GstDeinterlaceMethod {
|
||||||
|
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 {
|
||||||
|
GstObjectClass parent_class;
|
||||||
|
guint fields_required;
|
||||||
|
guint latency;
|
||||||
|
|
||||||
|
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 *nick;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_deinterlace_method_get_type (void);
|
||||||
|
|
||||||
|
gboolean gst_deinterlace_method_supported (GType type, GstVideoFormat format, gint width, gint height);
|
||||||
|
void gst_deinterlace_method_setup (GstDeinterlaceMethod * self, GstVideoFormat format, gint width, gint height);
|
||||||
|
void gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self, const GstDeinterlaceField * history, guint history_count, GstBuffer * outbuf);
|
||||||
|
gint gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self);
|
||||||
|
gint gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self);
|
||||||
|
|
||||||
|
#define GST_TYPE_DEINTERLACE_SIMPLE_METHOD (gst_deinterlace_simple_method_get_type ())
|
||||||
|
#define GST_IS_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
|
||||||
|
#define GST_IS_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
|
||||||
|
#define GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
|
||||||
|
#define GST_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethod))
|
||||||
|
#define GST_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
|
||||||
|
#define GST_DEINTERLACE_SIMPLE_METHOD_CAST(obj) ((GstDeinterlaceSimpleMethod*)(obj))
|
||||||
|
|
||||||
|
typedef struct _GstDeinterlaceSimpleMethod GstDeinterlaceSimpleMethod;
|
||||||
|
typedef struct _GstDeinterlaceSimpleMethodClass GstDeinterlaceSimpleMethodClass;
|
||||||
|
typedef struct _GstDeinterlaceScanlineData GstDeinterlaceScanlineData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This structure defines the simple deinterlacer plugin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct _GstDeinterlaceScanlineData {
|
||||||
|
const guint8 *tt0, *t0, *m0, *b0, *bb0;
|
||||||
|
const guint8 *tt1, *t1, *m1, *b1, *bb1;
|
||||||
|
const guint8 *tt2, *t2, *m2, *b2, *bb2;
|
||||||
|
const guint8 *tt3, *t3, *m3, *b3, *bb3;
|
||||||
|
gboolean bottom_field;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For interpolate_scanline the input is:
|
||||||
|
*
|
||||||
|
* | t-3 t-2 t-1 t
|
||||||
|
* | Field 3 | Field 2 | Field 1 | Field 0 |
|
||||||
|
* | TT3 | | TT1 | |
|
||||||
|
* | | T2 | | T0 |
|
||||||
|
* | M3 | | M1 | |
|
||||||
|
* | | B2 | | B0 |
|
||||||
|
* | BB3 | | BB1 | |
|
||||||
|
*
|
||||||
|
* For copy_scanline the input is:
|
||||||
|
*
|
||||||
|
* | t-3 t-2 t-1 t
|
||||||
|
* | Field 3 | Field 2 | Field 1 | Field 0 |
|
||||||
|
* | | TT2 | | TT0 |
|
||||||
|
* | T3 | | T1 | |
|
||||||
|
* | | M2 | | M0 |
|
||||||
|
* | B3 | | B1 | |
|
||||||
|
* | | BB2 | | BB0 |
|
||||||
|
*
|
||||||
|
* All other values are NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef void (*GstDeinterlaceSimpleMethodPackedFunction) (GstDeinterlaceSimpleMethod *self, guint8 *out, const GstDeinterlaceScanlineData *scanlines);
|
||||||
|
|
||||||
|
struct _GstDeinterlaceSimpleMethod {
|
||||||
|
GstDeinterlaceMethod parent;
|
||||||
|
|
||||||
|
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_packed;
|
||||||
|
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_packed;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstDeinterlaceSimpleMethodClass {
|
||||||
|
GstDeinterlaceMethodClass parent_class;
|
||||||
|
|
||||||
|
/* Packed formats */
|
||||||
|
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_yuy2;
|
||||||
|
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_yuy2;
|
||||||
|
GstDeinterlaceSimpleMethodPackedFunction interpolate_scanline_yvyu;
|
||||||
|
GstDeinterlaceSimpleMethodPackedFunction copy_scanline_yvyu;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_deinterlace_simple_method_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_DEINTERLACE_METHOD_H__ */
|
|
@ -32,7 +32,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_L (gst_deinterlace_method_greedy_l_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_L (gst_deinterlace_method_greedy_l_get_type ())
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "plugins.h"
|
#include "plugins.h"
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ())
|
||||||
#define GST_IS_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
|
#define GST_IS_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_LINEAR (gst_deinterlace_method_linear_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_LINEAR (gst_deinterlace_method_linear_get_type ())
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND (gst_deinterlace_method_linear_blend_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND (gst_deinterlace_method_linear_blend_get_type ())
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB (gst_deinterlace_method_scaler_bob_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB (gst_deinterlace_method_scaler_bob_get_type ())
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include "plugins.h"
|
#include "plugins.h"
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP (gst_deinterlace_method_tomsmocomp_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP (gst_deinterlace_method_tomsmocomp_get_type ())
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_VFIR (gst_deinterlace_method_vfir_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_VFIR (gst_deinterlace_method_vfir_get_type ())
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_WEAVE (gst_deinterlace_method_weave_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_WEAVE (gst_deinterlace_method_weave_get_type ())
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF (gst_deinterlace_method_weave_bff_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF (gst_deinterlace_method_weave_bff_get_type ())
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstdeinterlace.h"
|
#include "gstdeinterlacemethod.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF (gst_deinterlace_method_weave_tff_get_type ())
|
#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF (gst_deinterlace_method_weave_tff_get_type ())
|
||||||
|
|
Loading…
Reference in a new issue