diff --git a/gst/deinterlace2/gstdeinterlace2.c b/gst/deinterlace2/gstdeinterlace2.c index 26e9cd8f99..cf72a8d743 100644 --- a/gst/deinterlace2/gstdeinterlace2.c +++ b/gst/deinterlace2/gstdeinterlace2.c @@ -89,6 +89,169 @@ gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self) return klass->latency; } + +G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method, + GST_TYPE_DEINTERLACE_METHOD); + +static void +gst_deinterlace_simple_method_interpolate_scanline (GstDeinterlaceMethod * self, + GstDeinterlace2 * parent, guint8 * out, + GstDeinterlaceScanlineData * scanlines, gint width) +{ + memcpy (out, scanlines->m1, parent->line_length); +} + +static void +gst_deinterlace_simple_method_copy_scanline (GstDeinterlaceMethod * self, + GstDeinterlace2 * parent, guint8 * out, + GstDeinterlaceScanlineData * scanlines, gint width) +{ + memcpy (out, scanlines->m0, parent->line_length); +} + +static void +gst_deinterlace_simple_method_deinterlace_frame (GstDeinterlaceMethod * self, + GstDeinterlace2 * parent) +{ + GstDeinterlaceSimpleMethodClass *dsm_class = + GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self); + GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self); + GstDeinterlaceScanlineData scanlines; + guint8 *out = GST_BUFFER_DATA (parent->out_buf); + guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL; + gint cur_field_idx = parent->history_count - dm_class->fields_required; + guint cur_field_flags = parent->field_history[cur_field_idx].flags; + gint line; + + field0 = GST_BUFFER_DATA (parent->field_history[cur_field_idx].buf); + + g_assert (dm_class->fields_required <= 4); + + if (dm_class->fields_required >= 2) + field1 = field0 = + GST_BUFFER_DATA (parent->field_history[cur_field_idx + 1].buf); + if (dm_class->fields_required >= 3) + field1 = field0 = + GST_BUFFER_DATA (parent->field_history[cur_field_idx + 2].buf); + if (dm_class->fields_required >= 4) + field1 = field0 = + GST_BUFFER_DATA (parent->field_history[cur_field_idx + 3].buf); + + + if (cur_field_flags == PICTURE_INTERLACED_BOTTOM) { + /* double the first scanline of the bottom field */ + memcpy (out, field0, parent->line_length); + out += parent->output_stride; + } + + memcpy (out, field0, parent->line_length); + out += parent->output_stride; + + for (line = 2; line <= parent->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 + parent->field_stride; + + if (field1 != NULL) { + scanlines.tt1 = field1; + scanlines.m1 = field1 + parent->field_stride; + scanlines.bb1 = field1 + parent->field_stride * 2; + field1 += parent->field_stride; + } + + if (field2 != NULL) { + scanlines.t2 = field2; + scanlines.b2 = field2 + parent->field_stride; + } + + if (field3 != NULL) { + scanlines.tt3 = field3; + scanlines.m3 = field3 + parent->field_stride; + scanlines.bb3 = field3 + parent->field_stride * 2; + field3 += parent->field_stride; + } + + /* set valid data for corner cases */ + if (line == 2) { + scanlines.tt1 = scanlines.bb1; + scanlines.tt3 = scanlines.bb3; + } else if (line == parent->field_height) { + scanlines.bb1 = scanlines.tt1; + scanlines.bb3 = scanlines.tt3; + } + + dsm_class->interpolate_scanline (self, parent, out, &scanlines, + parent->frame_width); + out += parent->output_stride; + + memset (&scanlines, 0, sizeof (scanlines)); + scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM); + + /* copy a scanline */ + scanlines.tt0 = field0; + scanlines.m0 = field0 + parent->field_stride; + scanlines.bb0 = field0 + parent->field_stride * 2; + field0 += parent->field_stride; + + if (field1 != NULL) { + scanlines.t1 = field1; + scanlines.b1 = field1 + parent->field_stride; + } + + if (field2 != NULL) { + scanlines.tt2 = field2; + scanlines.m2 = field2 + parent->field_stride; + scanlines.bb2 = field2 + parent->field_stride * 2; + field2 += parent->field_stride; + } + + if (field3 != NULL) { + scanlines.t3 = field3; + scanlines.b3 = field3 + parent->field_stride; + } + + /* set valid data for corner cases */ + if (line == parent->field_height) { + scanlines.bb0 = scanlines.tt0; + scanlines.b1 = scanlines.t1; + scanlines.bb2 = scanlines.tt2; + scanlines.b3 = scanlines.t3; + } + + dsm_class->copy_scanline (self, parent, out, &scanlines, + parent->frame_width); + out += parent->output_stride; + } + + if (cur_field_flags == PICTURE_INTERLACED_TOP) { + /* double the last scanline of the top field */ + memcpy (out, field0, parent->line_length); + } +} + +static void +gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass * + klass) +{ + GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass; + + dm_class->deinterlace_frame = gst_deinterlace_simple_method_deinterlace_frame; + dm_class->fields_required = 2; + + klass->interpolate_scanline = + gst_deinterlace_simple_method_interpolate_scanline; + klass->copy_scanline = gst_deinterlace_simple_method_copy_scanline; +} + +static void +gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self) +{ +} + #define GST_TYPE_DEINTERLACE2_METHODS (gst_deinterlace2_methods_get_type ()) static GType gst_deinterlace2_methods_get_type (void) diff --git a/gst/deinterlace2/gstdeinterlace2.h b/gst/deinterlace2/gstdeinterlace2.h index ee9a201894..1f56dd3e0a 100644 --- a/gst/deinterlace2/gstdeinterlace2.h +++ b/gst/deinterlace2/gstdeinterlace2.h @@ -84,6 +84,68 @@ struct _GstDeinterlaceMethodClass { 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 { + guint8 *tt0, *t0, *m0, *b0, *bb0; + guint8 *tt1, *t1, *m1, *b1, *bb1; + guint8 *tt2, *t2, *m2, *b2, *bb2; + 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. + */ + +struct _GstDeinterlaceSimpleMethod { + GstDeinterlaceMethod parent; +}; + +struct _GstDeinterlaceSimpleMethodClass { + GstDeinterlaceMethodClass parent_class; + + void (*interpolate_scanline) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width); + void (*copy_scanline) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width); +}; + +GType gst_deinterlace_simple_method_get_type (void); + + #define MAX_FIELD_HISTORY 10 #define PICTURE_PROGRESSIVE 0