gstreamer/gst/deinterlace/gstdeinterlacemethod.c
David Schleef c2b343cd76 deinterlace: rewrite how neighboring scan lines are calculated
Old code was difficult to understand exactly how the neighboring
scan lines are calculated, and it appeared that some were off by
+2 or -2, depending on the field flag.  Fixes #639321.
2011-01-18 11:04:08 +01:00

737 lines
26 KiB
C

/*
* 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 "gstdeinterlacemethod.h"
G_DEFINE_ABSTRACT_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);
case GST_VIDEO_FORMAT_UYVY:
return (klass->deinterlace_frame_uyvy != NULL);
case GST_VIDEO_FORMAT_I420:
return (klass->deinterlace_frame_i420 != NULL);
case GST_VIDEO_FORMAT_YV12:
return (klass->deinterlace_frame_yv12 != NULL);
case GST_VIDEO_FORMAT_Y444:
return (klass->deinterlace_frame_y444 != NULL);
case GST_VIDEO_FORMAT_Y42B:
return (klass->deinterlace_frame_y42b != NULL);
case GST_VIDEO_FORMAT_Y41B:
return (klass->deinterlace_frame_y41b != NULL);
case GST_VIDEO_FORMAT_AYUV:
return (klass->deinterlace_frame_ayuv != NULL);
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_xRGB:
return (klass->deinterlace_frame_argb != NULL);
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_xBGR:
return (klass->deinterlace_frame_abgr != NULL);
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGBx:
return (klass->deinterlace_frame_rgba != NULL);
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_BGRx:
return (klass->deinterlace_frame_bgra != NULL);
case GST_VIDEO_FORMAT_RGB:
return (klass->deinterlace_frame_rgb != NULL);
case GST_VIDEO_FORMAT_BGR:
return (klass->deinterlace_frame_bgr != 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;
case GST_VIDEO_FORMAT_UYVY:
self->deinterlace_frame = klass->deinterlace_frame_uyvy;
break;
case GST_VIDEO_FORMAT_I420:
self->deinterlace_frame = klass->deinterlace_frame_i420;
break;
case GST_VIDEO_FORMAT_YV12:
self->deinterlace_frame = klass->deinterlace_frame_yv12;
break;
case GST_VIDEO_FORMAT_Y444:
self->deinterlace_frame = klass->deinterlace_frame_y444;
break;
case GST_VIDEO_FORMAT_Y42B:
self->deinterlace_frame = klass->deinterlace_frame_y42b;
break;
case GST_VIDEO_FORMAT_Y41B:
self->deinterlace_frame = klass->deinterlace_frame_y41b;
break;
case GST_VIDEO_FORMAT_AYUV:
self->deinterlace_frame = klass->deinterlace_frame_ayuv;
break;
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_xRGB:
self->deinterlace_frame = klass->deinterlace_frame_argb;
break;
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_xBGR:
self->deinterlace_frame = klass->deinterlace_frame_abgr;
break;
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGBx:
self->deinterlace_frame = klass->deinterlace_frame_rgba;
break;
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_BGRx:
self->deinterlace_frame = klass->deinterlace_frame_bgra;
break;
case GST_VIDEO_FORMAT_RGB:
self->deinterlace_frame = klass->deinterlace_frame_rgb;
break;
case GST_VIDEO_FORMAT_BGR:
self->deinterlace_frame = klass->deinterlace_frame_bgr;
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_ABSTRACT_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_ARGB:
case GST_VIDEO_FORMAT_xRGB:
return (klass->interpolate_scanline_argb != NULL
&& klass->copy_scanline_argb != NULL);
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGBx:
return (klass->interpolate_scanline_rgba != NULL
&& klass->copy_scanline_rgba != NULL);
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_xBGR:
return (klass->interpolate_scanline_abgr != NULL
&& klass->copy_scanline_abgr != NULL);
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_BGRx:
return (klass->interpolate_scanline_bgra != NULL
&& klass->copy_scanline_bgra != NULL);
case GST_VIDEO_FORMAT_RGB:
return (klass->interpolate_scanline_rgb != NULL
&& klass->copy_scanline_rgb != NULL);
case GST_VIDEO_FORMAT_BGR:
return (klass->interpolate_scanline_bgr != NULL
&& klass->copy_scanline_bgr != NULL);
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);
case GST_VIDEO_FORMAT_UYVY:
return (klass->interpolate_scanline_uyvy != NULL
&& klass->copy_scanline_uyvy != NULL);
case GST_VIDEO_FORMAT_AYUV:
return (klass->interpolate_scanline_ayuv != NULL
&& klass->copy_scanline_ayuv != NULL);
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
return (klass->interpolate_scanline_planar_y != NULL
&& klass->copy_scanline_planar_y != NULL &&
klass->interpolate_scanline_planar_u != NULL
&& klass->copy_scanline_planar_u != NULL &&
klass->interpolate_scanline_planar_v != NULL
&& klass->copy_scanline_planar_v != NULL);
default:
return FALSE;
}
}
static void
gst_deinterlace_simple_method_interpolate_scanline_packed
(GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
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)
{
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 *dest;
const guint8 *field0, *field1, *field2, *field3;
gint cur_field_idx = history_count - dm_class->fields_required;
guint cur_field_flags = history[cur_field_idx].flags;
gint i;
gint frame_height = self->parent.frame_height;
gint stride = self->parent.row_stride[0];
g_assert (self->interpolate_scanline_packed != NULL);
g_assert (self->copy_scanline_packed != NULL);
dest = GST_BUFFER_DATA (outbuf);
field0 = GST_BUFFER_DATA (history[cur_field_idx].buf);
g_assert (dm_class->fields_required <= 4);
if (dm_class->fields_required >= 2) {
field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf);
} else {
field1 = NULL;
}
if (dm_class->fields_required >= 3) {
field2 = GST_BUFFER_DATA (history[cur_field_idx + 2].buf);
} else {
field2 = NULL;
}
if (dm_class->fields_required >= 4) {
field3 = GST_BUFFER_DATA (history[cur_field_idx + 3].buf);
} else {
field3 = NULL;
}
#define CLAMP_LOW(i) (((i)<0) ? (i+2) : (i))
#define CLAMP_HI(i) (((i)>=(frame_height)) ? (i-2) : (i))
#define LINE(x,i) ((x) + CLAMP_HI(CLAMP_LOW(i)) * (stride))
#define LINE2(x,i) ((x) ? LINE(x,i) : NULL)
for (i = 0; i < frame_height; i++) {
memset (&scanlines, 0, sizeof (scanlines));
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
if (!((i & 1) ^ (cur_field_flags == PICTURE_INTERLACED_BOTTOM))) {
/* copying */
scanlines.tt0 = LINE2 (field0, (i - 2 >= 0) ? i - 2 : i);
scanlines.m0 = LINE2 (field0, i);
scanlines.bb0 = LINE2 (field0, (i + 2 < frame_height ? i + 2 : i));
scanlines.t1 = LINE2 (field1, i - 1);
scanlines.b1 = LINE2 (field1, i + 1);
scanlines.tt2 = LINE2 (field2, (i - 2 >= 0) ? i - 2 : i);
scanlines.m2 = LINE2 (field2, i);
scanlines.bb2 = LINE2 (field2, (i + 2 < frame_height ? i + 2 : i));
scanlines.t3 = LINE2 (field3, i - 1);
scanlines.b3 = LINE2 (field3, i + 1);
self->copy_scanline_packed (self, LINE (dest, i), &scanlines);
} else {
/* interpolating */
scanlines.t0 = LINE2 (field0, i - 1);
scanlines.b0 = LINE2 (field0, i + 1);
scanlines.tt1 = LINE2 (field1, (i - 2 >= 0) ? i - 2 : i);
scanlines.m1 = LINE2 (field1, i);
scanlines.bb1 = LINE2 (field1, (i + 2 < frame_height ? i + 2 : i));
scanlines.t2 = LINE2 (field2, i - 1);
scanlines.b2 = LINE2 (field2, i + 1);
scanlines.tt3 = LINE2 (field3, (i - 2 >= 0) ? i - 2 : i);
scanlines.m3 = LINE2 (field3, i);
scanlines.bb3 = LINE2 (field3, (i + 2 < frame_height ? i + 2 : i));
self->interpolate_scanline_packed (self, LINE (dest, i), &scanlines);
}
}
}
static void
gst_deinterlace_simple_method_interpolate_scanline_planar_y
(GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
}
static void
gst_deinterlace_simple_method_copy_scanline_planar_y (GstDeinterlaceSimpleMethod
* self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m0, self->parent.row_stride[0]);
}
static void
gst_deinterlace_simple_method_interpolate_scanline_planar_u
(GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[1]);
}
static void
gst_deinterlace_simple_method_copy_scanline_planar_u (GstDeinterlaceSimpleMethod
* self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m0, self->parent.row_stride[1]);
}
static void
gst_deinterlace_simple_method_interpolate_scanline_planar_v
(GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[2]);
}
static void
gst_deinterlace_simple_method_copy_scanline_planar_v (GstDeinterlaceSimpleMethod
* self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m0, self->parent.row_stride[2]);
}
static void
gst_deinterlace_simple_method_deinterlace_frame_planar_plane
(GstDeinterlaceSimpleMethod * self, guint8 * dest, const guint8 * field0,
const guint8 * field1, const guint8 * field2, const guint8 * field3,
guint cur_field_flags,
gint plane, GstDeinterlaceSimpleMethodFunction copy_scanline,
GstDeinterlaceSimpleMethodFunction interpolate_scanline)
{
GstDeinterlaceScanlineData scanlines;
gint i;
gint frame_height = self->parent.height[plane];
gint stride = self->parent.row_stride[plane];
g_assert (interpolate_scanline != NULL);
g_assert (copy_scanline != NULL);
for (i = 0; i < frame_height; i++) {
memset (&scanlines, 0, sizeof (scanlines));
scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
if (!((i & 1) ^ (cur_field_flags == PICTURE_INTERLACED_BOTTOM))) {
/* copying */
scanlines.tt0 = LINE2 (field0, (i - 2 >= 0) ? i - 2 : i);
scanlines.m0 = LINE2 (field0, i);
scanlines.bb0 = LINE2 (field0, (i + 2 < frame_height ? i + 2 : i));
scanlines.t1 = LINE2 (field1, i - 1);
scanlines.b1 = LINE2 (field1, i + 1);
scanlines.tt2 = LINE2 (field2, (i - 2 >= 0) ? i - 2 : i);
scanlines.m2 = LINE2 (field2, i);
scanlines.bb2 = LINE2 (field2, (i + 2 < frame_height ? i + 2 : i));
scanlines.t3 = LINE2 (field3, i - 1);
scanlines.b3 = LINE2 (field3, i + 1);
copy_scanline (self, LINE (dest, i), &scanlines);
} else {
/* interpolating */
scanlines.t0 = LINE2 (field0, i - 1);
scanlines.b0 = LINE2 (field0, i + 1);
scanlines.tt1 = LINE2 (field1, (i - 2 >= 0) ? i - 2 : i);
scanlines.m1 = LINE2 (field1, i);
scanlines.bb1 = LINE2 (field1, (i + 2 < frame_height ? i + 2 : i));
scanlines.t2 = LINE2 (field2, i - 1);
scanlines.b2 = LINE2 (field2, i + 1);
scanlines.tt3 = LINE2 (field3, (i - 2 >= 0) ? i - 2 : i);
scanlines.m3 = LINE2 (field3, i);
scanlines.bb3 = LINE2 (field3, (i + 2 < frame_height ? i + 2 : i));
interpolate_scanline (self, LINE (dest, i), &scanlines);
}
}
}
static void
gst_deinterlace_simple_method_deinterlace_frame_planar (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);
guint8 *out;
const guint8 *field0, *field1, *field2, *field3;
gint cur_field_idx = history_count - dm_class->fields_required;
guint cur_field_flags = history[cur_field_idx].flags;
gint i, offset;
GstDeinterlaceSimpleMethodFunction copy_scanline;
GstDeinterlaceSimpleMethodFunction interpolate_scanline;
g_assert (self->interpolate_scanline_planar[0] != NULL);
g_assert (self->interpolate_scanline_planar[1] != NULL);
g_assert (self->interpolate_scanline_planar[2] != NULL);
g_assert (self->copy_scanline_planar[0] != NULL);
g_assert (self->copy_scanline_planar[1] != NULL);
g_assert (self->copy_scanline_planar[2] != NULL);
for (i = 0; i < 3; i++) {
offset = self->parent.offset[i];
copy_scanline = self->copy_scanline_planar[i];
interpolate_scanline = self->interpolate_scanline_planar[i];
out = GST_BUFFER_DATA (outbuf) + offset;
field0 = GST_BUFFER_DATA (history[cur_field_idx].buf) + offset;
g_assert (dm_class->fields_required <= 4);
field1 = NULL;
if (dm_class->fields_required >= 2) {
field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf) + offset;
}
field2 = NULL;
if (dm_class->fields_required >= 3) {
field2 = GST_BUFFER_DATA (history[cur_field_idx + 2].buf) + offset;
}
field3 = NULL;
if (dm_class->fields_required >= 4) {
field3 = GST_BUFFER_DATA (history[cur_field_idx + 3].buf) + offset;
}
gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self, out,
field0, field1, field2, field3, cur_field_flags, i, copy_scanline,
interpolate_scanline);
}
}
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;
self->interpolate_scanline_planar[0] = NULL;
self->interpolate_scanline_planar[1] = NULL;
self->interpolate_scanline_planar[2] = NULL;
self->copy_scanline_planar[0] = NULL;
self->copy_scanline_planar[1] = NULL;
self->copy_scanline_planar[2] = 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;
case GST_VIDEO_FORMAT_UYVY:
self->interpolate_scanline_packed = klass->interpolate_scanline_uyvy;
self->copy_scanline_packed = klass->copy_scanline_uyvy;
break;
case GST_VIDEO_FORMAT_AYUV:
self->interpolate_scanline_packed = klass->interpolate_scanline_ayuv;
self->copy_scanline_packed = klass->copy_scanline_ayuv;
break;
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_xRGB:
self->interpolate_scanline_packed = klass->interpolate_scanline_argb;
self->copy_scanline_packed = klass->copy_scanline_argb;
break;
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_xBGR:
self->interpolate_scanline_packed = klass->interpolate_scanline_abgr;
self->copy_scanline_packed = klass->copy_scanline_abgr;
break;
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGBx:
self->interpolate_scanline_packed = klass->interpolate_scanline_rgba;
self->copy_scanline_packed = klass->copy_scanline_rgba;
break;
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_BGRx:
self->interpolate_scanline_packed = klass->interpolate_scanline_bgra;
self->copy_scanline_packed = klass->copy_scanline_bgra;
break;
case GST_VIDEO_FORMAT_RGB:
self->interpolate_scanline_packed = klass->interpolate_scanline_rgb;
self->copy_scanline_packed = klass->copy_scanline_rgb;
break;
case GST_VIDEO_FORMAT_BGR:
self->interpolate_scanline_packed = klass->interpolate_scanline_bgr;
self->copy_scanline_packed = klass->copy_scanline_bgr;
break;
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
self->interpolate_scanline_planar[0] =
klass->interpolate_scanline_planar_y;
self->copy_scanline_planar[0] = klass->copy_scanline_planar_y;
self->interpolate_scanline_planar[1] =
klass->interpolate_scanline_planar_u;
self->copy_scanline_planar[1] = klass->copy_scanline_planar_u;
self->interpolate_scanline_planar[2] =
klass->interpolate_scanline_planar_v;
self->copy_scanline_planar[2] = klass->copy_scanline_planar_v;
break;
default:
break;
}
}
static void
gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass
* klass)
{
GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
dm_class->deinterlace_frame_ayuv =
gst_deinterlace_simple_method_deinterlace_frame_packed;
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->deinterlace_frame_uyvy =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_argb =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_abgr =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_rgba =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_bgra =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_rgb =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_bgr =
gst_deinterlace_simple_method_deinterlace_frame_packed;
dm_class->deinterlace_frame_i420 =
gst_deinterlace_simple_method_deinterlace_frame_planar;
dm_class->deinterlace_frame_yv12 =
gst_deinterlace_simple_method_deinterlace_frame_planar;
dm_class->deinterlace_frame_y444 =
gst_deinterlace_simple_method_deinterlace_frame_planar;
dm_class->deinterlace_frame_y42b =
gst_deinterlace_simple_method_deinterlace_frame_planar;
dm_class->deinterlace_frame_y41b =
gst_deinterlace_simple_method_deinterlace_frame_planar;
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;
klass->interpolate_scanline_ayuv =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_ayuv =
gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_uyvy =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_uyvy =
gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_argb =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_argb =
gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_abgr =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_abgr =
gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_rgba =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_rgba =
gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_bgra =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_bgra =
gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_rgb =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_rgb = gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_bgr =
gst_deinterlace_simple_method_interpolate_scanline_packed;
klass->copy_scanline_bgr = gst_deinterlace_simple_method_copy_scanline_packed;
klass->interpolate_scanline_planar_y =
gst_deinterlace_simple_method_interpolate_scanline_planar_y;
klass->copy_scanline_planar_y =
gst_deinterlace_simple_method_copy_scanline_planar_y;
klass->interpolate_scanline_planar_u =
gst_deinterlace_simple_method_interpolate_scanline_planar_u;
klass->copy_scanline_planar_u =
gst_deinterlace_simple_method_copy_scanline_planar_u;
klass->interpolate_scanline_planar_v =
gst_deinterlace_simple_method_interpolate_scanline_planar_v;
klass->copy_scanline_planar_v =
gst_deinterlace_simple_method_copy_scanline_planar_v;
}
static void
gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
{
}