summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--gst/deinterlace2/gstdeinterlace2.c163
-rw-r--r--gst/deinterlace2/gstdeinterlace2.h62
3 files changed, 238 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 4f1a36a4..23b8a7a1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2008-08-02 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * gst/deinterlace2/gstdeinterlace2.c:
+ (gst_deinterlace_simple_method_interpolate_scanline),
+ (gst_deinterlace_simple_method_copy_scanline),
+ (gst_deinterlace_simple_method_deinterlace_frame),
+ (gst_deinterlace_simple_method_class_init),
+ (gst_deinterlace_simple_method_init):
+ * gst/deinterlace2/gstdeinterlace2.h:
+ Add a GstDeinterlaceSimpleMethod subclass of GstDeinterlaceMethod that
+ can be used by simple deinterlacing methods. They only have to provide
+ a function for interpolating a scanline or copying a scanline.
+
+2008-08-02 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+
* gst/deinterlace2/gstdeinterlace2.c: (gst_deinterlace2_chain):
Respect the latency of the deinterlacing algorithm for the timestamps
of every buffer.
diff --git a/gst/deinterlace2/gstdeinterlace2.c b/gst/deinterlace2/gstdeinterlace2.c
index 26e9cd8f..cf72a8d7 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 ee9a2018..1f56dd3e 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