deinterlace: change field handling through methods

This likely breaks stuff.  The good: all of the methods now create
field images aligned with input frames, without timestamp mangling.
The bad: this touches a lot of code, much of which is hairy and in
need of cleanup.  However, at this point we can reasonably create a
PSNR-based test.
This commit is contained in:
David Schleef 2011-07-10 21:40:20 -07:00
parent ad996feb28
commit 0446787e65
13 changed files with 325 additions and 191 deletions

View file

@ -765,6 +765,7 @@ gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
self->state_count = 0;
self->pattern_lock = FALSE;
self->pattern_refresh = TRUE;
self->cur_field_idx = -1;
if (!self->still_frame_mode && self->last_buffer) {
gst_buffer_unref (self->last_buffer);
@ -1183,9 +1184,10 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
}
self->history_count += fields_to_push;
self->cur_field_idx += fields_to_push;
GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d",
self->history_count);
GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
self->history_count, self->cur_field_idx);
if (self->last_buffer)
gst_buffer_unref (self->last_buffer);
@ -1456,7 +1458,6 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
GstClockTime timestamp;
GstFlowReturn ret;
gint fields_required;
gint cur_field_idx;
GstBuffer *buf, *outbuf;
GstDeinterlaceField *field1, *field2;
GstDeinterlaceInterlacingMethod interlacing_method;
@ -1471,7 +1472,6 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
restart:
ret = GST_FLOW_OK;
fields_required = 0;
cur_field_idx = 0;
hl_no_lock = FALSE;
same_buffer = FALSE;
flush_one = FALSE;
@ -1530,6 +1530,7 @@ restart:
if (flush_one && self->drop_orphans) {
GST_DEBUG_OBJECT (self, "Dropping orphan first field");
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
goto restart;
}
@ -1558,7 +1559,7 @@ restart:
fields_required = 2;
if (!flushing && self->history_count < fields_required) {
GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
self->history_count, fields_required);
self->history_count, self->cur_field_idx + fields_required);
goto need_more;
}
@ -1573,9 +1574,11 @@ restart:
GST_DEBUG_OBJECT (self,
"Frame type: Telecine Progressive; pushing buffer as a frame");
/* pop and push */
self->cur_field_idx--;
field1_buf = gst_deinterlace_pop_history (self);
/* field2 is the same buffer as field1, but we need to remove it from
* the history anyway */
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
/* set the caps from the src pad on the buffer as they should be correct */
gst_buffer_set_caps (field1_buf, GST_PAD_CAPS (self->srcpad));
@ -1617,9 +1620,9 @@ restart:
}
/* Not enough fields in the history */
if (self->history_count < fields_required) {
if (!flushing && self->history_count < fields_required) {
GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
self->history_count, fields_required);
self->history_count, self->cur_field_idx + fields_required);
goto need_more;
}
@ -1633,9 +1636,9 @@ restart:
fields_required = 2;
/* Not enough fields in the history */
if (self->history_count < fields_required) {
if (!flushing && self->history_count < fields_required) {
GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
self->history_count, fields_required);
self->history_count, self->cur_field_idx + fields_required);
goto need_more;
}
@ -1649,9 +1652,11 @@ restart:
GST_DEBUG_OBJECT (self,
"Frame type: Progressive; pushing buffer as a frame");
/* pop and push */
self->cur_field_idx--;
field1_buf = gst_deinterlace_pop_history (self);
/* field2 is the same buffer as field1, but we need to remove it from the
* history anyway */
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
GST_DEBUG_OBJECT (self,
"[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
@ -1662,6 +1667,10 @@ restart:
return gst_pad_push (self->srcpad, field1_buf);
}
if (!flushing && self->cur_field_idx < 1) {
goto need_more;
}
if (self->fields == GST_DEINTERLACE_ALL
|| interlacing_method == GST_DEINTERLACE_TELECINE)
GST_DEBUG_OBJECT (self, "All fields");
@ -1670,9 +1679,7 @@ restart:
else if (self->fields == GST_DEINTERLACE_BF)
GST_DEBUG_OBJECT (self, "Bottom fields");
cur_field_idx = self->history_count - fields_required;
if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
&& (self->fields == GST_DEINTERLACE_TF
|| interlacing_method == GST_DEINTERLACE_TELECINE))
|| self->fields == GST_DEINTERLACE_ALL) {
@ -1723,16 +1730,37 @@ restart:
/* Check if we need to drop the frame because of QoS */
if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
gst_buffer_unref (outbuf);
outbuf = NULL;
ret = GST_FLOW_OK;
} else {
if (self->cur_field_idx < 0 && flushing) {
if (self->history_count == 1) {
gst_buffer_unref (gst_deinterlace_pop_history (self));
goto need_more;
}
self->cur_field_idx++;
}
if (self->cur_field_idx < 0) {
goto need_more;
}
if (!flushing && self->cur_field_idx < 1) {
goto need_more;
}
/* do magic calculus */
gst_deinterlace_method_deinterlace_frame (self->method,
self->field_history, self->history_count, outbuf);
self->field_history, self->history_count, outbuf,
self->cur_field_idx);
gst_buffer_unref (gst_deinterlace_pop_history (self));
self->cur_field_idx--;
if (self->cur_field_idx + 1 +
gst_deinterlace_method_get_latency (self->method)
< self->history_count || flushing) {
gst_buffer_unref (gst_deinterlace_pop_history (self));
}
if (gst_deinterlace_clip_buffer (self, outbuf)) {
GST_DEBUG_OBJECT (self,
@ -1755,6 +1783,7 @@ restart:
/* pop off the second field */
GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
self->history_count);
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
interlacing_method = GST_DEINTERLACE_INTERLACED;
return ret;
@ -1767,10 +1796,11 @@ restart:
}
}
/* no calculation done: remove excess field */
else if (self->field_history[cur_field_idx].flags ==
else if (self->field_history[self->cur_field_idx].flags ==
PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
&& interlacing_method != GST_DEINTERLACE_TELECINE)) {
GST_DEBUG_OBJECT (self, "Removing unused top field");
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
if (flush_one && !self->drop_orphans) {
@ -1779,13 +1809,19 @@ restart:
}
}
cur_field_idx = self->history_count - fields_required;
if (self->history_count < fields_required)
return ret;
if (self->cur_field_idx < 0)
return ret;
if (!flushing && self->cur_field_idx < 1) {
return ret;
}
/* deinterlace bottom_field */
if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
&& (self->fields == GST_DEINTERLACE_BF
if ((self->field_history[self->cur_field_idx].flags ==
PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
|| interlacing_method == GST_DEINTERLACE_TELECINE))
|| self->fields == GST_DEINTERLACE_ALL) {
GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
@ -1834,6 +1870,7 @@ restart:
/* Check if we need to drop the frame because of QoS */
if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
gst_buffer_unref (outbuf);
outbuf = NULL;
@ -1841,9 +1878,15 @@ restart:
} else {
/* do magic calculus */
gst_deinterlace_method_deinterlace_frame (self->method,
self->field_history, self->history_count, outbuf);
self->field_history, self->history_count, outbuf,
self->cur_field_idx);
gst_buffer_unref (gst_deinterlace_pop_history (self));
self->cur_field_idx--;
if (self->cur_field_idx + 1 +
gst_deinterlace_method_get_latency (self->method)
< self->history_count) {
gst_buffer_unref (gst_deinterlace_pop_history (self));
}
if (gst_deinterlace_clip_buffer (self, outbuf)) {
GST_DEBUG_OBJECT (self,
@ -1866,6 +1909,7 @@ restart:
/* pop off the second field */
GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
self->history_count);
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
interlacing_method = GST_DEINTERLACE_INTERLACED;
return ret;
@ -1878,10 +1922,11 @@ restart:
}
}
/* no calculation done: remove excess field */
else if (self->field_history[cur_field_idx].flags ==
else if (self->field_history[self->cur_field_idx].flags ==
PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
&& interlacing_method != GST_DEINTERLACE_TELECINE)) {
GST_DEBUG_OBJECT (self, "Removing unused bottom field");
self->cur_field_idx--;
gst_buffer_unref (gst_deinterlace_pop_history (self));
if (flush_one && !self->drop_orphans) {

View file

@ -146,6 +146,7 @@ struct _GstDeinterlace
*/
GstDeinterlaceField field_history[GST_DEINTERLACE_MAX_FIELD_HISTORY];
guint history_count;
int cur_field_idx;
/* Set to TRUE if we're in still frame mode,
i.e. just forward all buffers

View file

@ -206,10 +206,10 @@ gst_deinterlace_method_init (GstDeinterlaceMethod * self)
void
gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
GstBuffer * outbuf, int cur_field_idx)
{
g_assert (self->deinterlace_frame != NULL);
self->deinterlace_frame (self, history, history_count, outbuf);
self->deinterlace_frame (self, history, history_count, outbuf, cur_field_idx);
}
gint
@ -318,14 +318,13 @@ gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod *
static void
gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
method, const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
GstBuffer * outbuf, gint cur_field_idx)
{
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;
const guint8 *field0, *field1, *field2, *fieldp;
guint cur_field_flags = history[cur_field_idx].flags;
gint i;
gint frame_height = self->parent.frame_height;
@ -334,29 +333,29 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
g_assert (self->interpolate_scanline_packed != NULL);
g_assert (self->copy_scanline_packed != NULL);
if (cur_field_idx > 0) {
fieldp = GST_BUFFER_DATA (history[cur_field_idx - 1].buf);
} else {
fieldp = 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) {
if (cur_field_idx + 1 < history_count) {
field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf);
} else {
field1 = NULL;
}
if (dm_class->fields_required >= 3) {
if (cur_field_idx + 2 < history_count) {
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))
@ -368,6 +367,9 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
if (!((i & 1) ^ scanlines.bottom_field)) {
/* copying */
scanlines.tp = LINE2 (fieldp, i - 1);
scanlines.bp = LINE2 (fieldp, i + 1);
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));
@ -379,12 +381,13 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
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.ttp = LINE2 (fieldp, (i - 2 >= 0) ? i - 2 : i);
scanlines.mp = LINE2 (fieldp, i);
scanlines.bbp = LINE2 (fieldp, (i + 2 < frame_height ? i + 2 : i));
scanlines.t0 = LINE2 (field0, i - 1);
scanlines.b0 = LINE2 (field0, i + 1);
@ -395,10 +398,6 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod *
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);
}
}
@ -452,7 +451,7 @@ gst_deinterlace_simple_method_copy_scanline_planar_v (GstDeinterlaceSimpleMethod
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,
const guint8 * field1, const guint8 * field2, const guint8 * fieldp,
guint cur_field_flags,
gint plane, GstDeinterlaceSimpleMethodFunction copy_scanline,
GstDeinterlaceSimpleMethodFunction interpolate_scanline)
@ -471,6 +470,9 @@ static void
if (!((i & 1) ^ scanlines.bottom_field)) {
/* copying */
scanlines.tp = LINE2 (fieldp, i - 1);
scanlines.bp = LINE2 (fieldp, i + 1);
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));
@ -482,12 +484,13 @@ static void
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.ttp = LINE2 (fieldp, (i - 2 >= 0) ? i - 2 : i);
scanlines.mp = LINE2 (fieldp, i);
scanlines.bbp = LINE2 (fieldp, (i + 2 < frame_height ? i + 2 : i));
scanlines.t0 = LINE2 (field0, i - 1);
scanlines.b0 = LINE2 (field0, i + 1);
@ -498,10 +501,6 @@ static void
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);
}
}
@ -510,13 +509,12 @@ static void
static void
gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod *
method, const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
GstBuffer * outbuf, gint cur_field_idx)
{
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;
const guint8 *field0, *field1, *field2, *fieldp;
guint cur_field_flags = history[cur_field_idx].flags;
gint i, offset;
GstDeinterlaceSimpleMethodFunction copy_scanline;
@ -536,27 +534,27 @@ gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod *
out = GST_BUFFER_DATA (outbuf) + offset;
fieldp = NULL;
if (cur_field_idx > 0) {
fieldp = GST_BUFFER_DATA (history[cur_field_idx - 1].buf) + 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) {
if (cur_field_idx + 1 < history_count) {
field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf) + offset;
}
field2 = NULL;
if (dm_class->fields_required >= 3) {
if (cur_field_idx + 2 < history_count) {
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,
field0, field1, field2, fieldp, cur_field_flags, i, copy_scanline,
interpolate_scanline);
}
}
@ -564,13 +562,12 @@ gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod *
static void
gst_deinterlace_simple_method_deinterlace_frame_nv12 (GstDeinterlaceMethod *
method, const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
GstBuffer * outbuf, gint cur_field_idx)
{
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;
const guint8 *field0, *field1, *field2, *fieldp;
guint cur_field_flags = history[cur_field_idx].flags;
gint i, offset;
@ -582,27 +579,27 @@ gst_deinterlace_simple_method_deinterlace_frame_nv12 (GstDeinterlaceMethod *
out = GST_BUFFER_DATA (outbuf) + offset;
fieldp = NULL;
if (cur_field_idx > 0) {
fieldp = GST_BUFFER_DATA (history[cur_field_idx - 1].buf) + 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) {
if (cur_field_idx + 1 < history_count) {
field1 = GST_BUFFER_DATA (history[cur_field_idx + 1].buf) + offset;
}
field2 = NULL;
if (dm_class->fields_required >= 3) {
if (cur_field_idx + 2 < history_count) {
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,
field0, field1, field2, fieldp, cur_field_flags, i,
self->copy_scanline_packed, self->interpolate_scanline_packed);
}
}

View file

@ -61,7 +61,9 @@ typedef struct
* This structure defines the deinterlacer plugin.
*/
typedef void (*GstDeinterlaceMethodDeinterlaceFunction) (GstDeinterlaceMethod *self, const GstDeinterlaceField *history, guint history_count, GstBuffer *outbuf);
typedef void (*GstDeinterlaceMethodDeinterlaceFunction) (
GstDeinterlaceMethod *self, const GstDeinterlaceField *history,
guint history_count, GstBuffer *outbuf, int cur_field_idx);
struct _GstDeinterlaceMethod {
GstObject parent;
@ -112,7 +114,8 @@ 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);
void gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self, const GstDeinterlaceField * history, guint history_count, GstBuffer * outbuf,
int cur_field_idx);
gint gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self);
gint gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self);
@ -133,32 +136,32 @@ typedef struct _GstDeinterlaceScanlineData GstDeinterlaceScanlineData;
*/
struct _GstDeinterlaceScanlineData {
const guint8 *ttp, *tp, *mp, *bp, *bbp;
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 | |
* | t-3 t-2 t-1 t t+1
* | Field 3 | Field 2 | Field 1 | Field 0 | Field -1
* | TT3 | | TT1 | | TTp
* | | T2 | | T0 |
* | M3 | | M1 | |
* | M3 | | M1 | | Mp
* | | B2 | | B0 |
* | BB3 | | BB1 | |
* | BB3 | | BB1 | | BBp
*
* For copy_scanline the input is:
*
* | t-3 t-2 t-1 t
* | Field 3 | Field 2 | Field 1 | Field 0 |
* | t-3 t-2 t-1 t t+1
* | Field 3 | Field 2 | Field 1 | Field 0 | Field -1
* | | TT2 | | TT0 |
* | T3 | | T1 | |
* | T3 | | T1 | | Tp
* | | M2 | | M0 |
* | B3 | | B1 | |
* | B3 | | B1 | | Bp
* | | BB2 | | BB0 |
*
* All other values are NULL.

View file

@ -72,54 +72,69 @@ static inline void
deinterlace_greedy_interpolate_scanline_orc (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME - is this safe or just a hack? */
guint max_comb = GST_DEINTERLACE_METHOD_GREEDY_L (self)->max_comb;
deinterlace_line_greedy (out, scanlines->m3, scanlines->t2, scanlines->b2,
scanlines->m1, max_comb, self->parent.row_stride[0]);
if (scanlines->m1 == NULL || scanlines->mp == NULL) {
deinterlace_line_linear (out, scanlines->t0, scanlines->b0,
self->parent.row_stride[0]);
} else {
deinterlace_line_greedy (out, scanlines->m1, scanlines->t0, scanlines->b0,
scanlines->mp ? scanlines->mp : scanlines->m1,
max_comb, self->parent.row_stride[0]);
}
}
static inline void
deinterlace_greedy_interpolate_scanline_orc_planar_u (GstDeinterlaceSimpleMethod
* self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME - is this safe or just a hack? */
guint max_comb = GST_DEINTERLACE_METHOD_GREEDY_L (self)->max_comb;
deinterlace_line_greedy (out, scanlines->m3, scanlines->t2, scanlines->b2,
scanlines->m1, max_comb, self->parent.row_stride[1]);
if (scanlines->m1 == NULL || scanlines->mp == NULL) {
deinterlace_line_linear (out, scanlines->t0, scanlines->b0,
self->parent.row_stride[1]);
} else {
deinterlace_line_greedy (out, scanlines->m1, scanlines->t0, scanlines->b0,
scanlines->mp ? scanlines->mp : scanlines->m1,
max_comb, self->parent.row_stride[1]);
}
}
static inline void
deinterlace_greedy_interpolate_scanline_orc_planar_v (GstDeinterlaceSimpleMethod
* self, guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME - is this safe or just a hack? */
guint max_comb = GST_DEINTERLACE_METHOD_GREEDY_L (self)->max_comb;
deinterlace_line_greedy (out, scanlines->m3, scanlines->t2, scanlines->b2,
scanlines->m1, max_comb, self->parent.row_stride[2]);
if (scanlines->m1 == NULL || scanlines->mp == NULL) {
deinterlace_line_linear (out, scanlines->t0, scanlines->b0,
self->parent.row_stride[2]);
} else {
deinterlace_line_greedy (out, scanlines->m1, scanlines->t0, scanlines->b0,
scanlines->mp ? scanlines->mp : scanlines->m1,
max_comb, self->parent.row_stride[2]);
}
}
static void
deinterlace_greedy_copy_scanline (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m2, self->parent.row_stride[0]);
memcpy (out, scanlines->m0, self->parent.row_stride[0]);
}
static void
deinterlace_greedy_copy_scanline_planar_u (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m2, self->parent.row_stride[1]);
memcpy (out, scanlines->m0, self->parent.row_stride[1]);
}
static void
deinterlace_greedy_copy_scanline_planar_v (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m2, self->parent.row_stride[2]);
memcpy (out, scanlines->m0, self->parent.row_stride[2]);
}
G_DEFINE_TYPE (GstDeinterlaceMethodGreedyL, gst_deinterlace_method_greedy_l,
@ -179,7 +194,7 @@ gst_deinterlace_method_greedy_l_class_init (GstDeinterlaceMethodGreedyLClass *
"Max Comb", 0, 255, 15, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
);
dim_class->fields_required = 4;
dim_class->fields_required = 2;
dim_class->name = "Motion Adaptive: Simple Detection";
dim_class->nick = "greedyl";
dim_class->latency = 1;

View file

@ -719,7 +719,7 @@ greedyh_scanline_C_planar_uv (GstDeinterlaceMethodGreedyH * self,
static void
deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
GstBuffer * outbuf, int cur_field_idx)
{
GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
GstDeinterlaceMethodGreedyHClass *klass =
@ -736,6 +736,23 @@ deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
guint8 *Dest = GST_BUFFER_DATA (outbuf);
ScanlineFunction scanline;
if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
GstDeinterlaceMethod *backup_method;
backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
NULL);
gst_deinterlace_method_setup (backup_method, method->format,
method->frame_width, method->frame_height);
gst_deinterlace_method_deinterlace_frame (backup_method,
history, history_count, outbuf, cur_field_idx);
g_object_unref (backup_method);
return;
}
cur_field_idx += 2;
switch (method->format) {
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_YVYU:
@ -755,20 +772,20 @@ deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
// copy first even line no matter what, and the first odd line if we're
// processing an EVEN field. (note diff from other deint rtns.)
if (history[history_count - 1].flags == PICTURE_INTERLACED_BOTTOM) {
if (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM) {
InfoIsOdd = 1;
L1 = GST_BUFFER_DATA (history[history_count - 2].buf);
if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 = GST_BUFFER_DATA (history[cur_field_idx - 2].buf);
if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 += RowStride;
L2 = GST_BUFFER_DATA (history[history_count - 1].buf);
if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 = GST_BUFFER_DATA (history[cur_field_idx - 1].buf);
if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 += RowStride;
L3 = L1 + Pitch;
L2P = GST_BUFFER_DATA (history[history_count - 3].buf);
if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P = GST_BUFFER_DATA (history[cur_field_idx - 3].buf);
if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P += RowStride;
// copy first even line
@ -776,17 +793,17 @@ deinterlace_frame_di_greedyh_packed (GstDeinterlaceMethod * method,
Dest += RowStride;
} else {
InfoIsOdd = 0;
L1 = GST_BUFFER_DATA (history[history_count - 2].buf);
if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 = GST_BUFFER_DATA (history[cur_field_idx - 2].buf);
if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 += RowStride;
L2 = GST_BUFFER_DATA (history[history_count - 1].buf) + Pitch;
if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 = GST_BUFFER_DATA (history[cur_field_idx - 1].buf) + Pitch;
if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 += RowStride;
L3 = L1 + Pitch;
L2P = GST_BUFFER_DATA (history[history_count - 3].buf) + Pitch;
if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P = GST_BUFFER_DATA (history[cur_field_idx - 3].buf) + Pitch;
if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P += RowStride;
// copy first even line
@ -858,7 +875,7 @@ deinterlace_frame_di_greedyh_planar_plane (GstDeinterlaceMethodGreedyH * self,
static void
deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method,
const GstDeinterlaceField * history, guint history_count,
GstBuffer * outbuf)
GstBuffer * outbuf, int cur_field_idx)
{
GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method);
GstDeinterlaceMethodGreedyHClass *klass =
@ -876,10 +893,27 @@ deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method,
gint Offset;
ScanlineFunction scanline;
if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
GstDeinterlaceMethod *backup_method;
backup_method = g_object_new (gst_deinterlace_method_linear_get_type (),
NULL);
gst_deinterlace_method_setup (backup_method, method->format,
method->frame_width, method->frame_height);
gst_deinterlace_method_deinterlace_frame (backup_method,
history, history_count, outbuf, cur_field_idx);
g_object_unref (backup_method);
return;
}
cur_field_idx += 2;
for (i = 0; i < 3; i++) {
Offset = method->offset[i];
InfoIsOdd = (history[history_count - 1].flags == PICTURE_INTERLACED_BOTTOM);
InfoIsOdd = (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM);
RowStride = method->row_stride[i];
FieldHeight = method->height[i] / 2;
Pitch = method->row_stride[i] * 2;
@ -891,17 +925,17 @@ deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method,
Dest = GST_BUFFER_DATA (outbuf) + Offset;
L1 = GST_BUFFER_DATA (history[history_count - 2].buf) + Offset;
if (history[history_count - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 = GST_BUFFER_DATA (history[cur_field_idx - 2].buf) + Offset;
if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM)
L1 += RowStride;
L2 = GST_BUFFER_DATA (history[history_count - 1].buf) + Offset;
if (history[history_count - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 = GST_BUFFER_DATA (history[cur_field_idx - 1].buf) + Offset;
if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM)
L2 += RowStride;
L3 = L1 + Pitch;
L2P = GST_BUFFER_DATA (history[history_count - 3].buf) + Offset;
if (history[history_count - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P = GST_BUFFER_DATA (history[cur_field_idx - 3].buf) + Offset;
if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM)
L2P += RowStride;
deinterlace_frame_di_greedyh_planar_plane (self, L1, L2, L3, L2P, Dest,

View file

@ -56,7 +56,11 @@ deinterlace_scanline_linear_blend_c (GstDeinterlaceSimpleMethod * self,
guint8 * out, const guint8 * t0, const guint8 * b0, const guint8 * m1,
gint size)
{
deinterlace_line_linear_blend (out, t0, b0, m1, size);
if (m1 == NULL) {
deinterlace_line_linear (out, t0, b0, size);
} else {
deinterlace_line_linear_blend (out, t0, b0, m1, size);
}
}
static void
@ -96,7 +100,11 @@ deinterlace_scanline_linear_blend2_c (GstDeinterlaceSimpleMethod * self,
guint8 * out, const guint8 * m0, const guint8 * t1, const guint8 * b1,
gint size)
{
deinterlace_line_linear_blend (out, t1, b1, m0, size);
if (t1 == NULL) {
memcpy (out, m0, size);
} else {
deinterlace_line_linear_blend (out, t1, b1, m0, size);
}
}
static void
@ -145,7 +153,7 @@ static void
dim_class->fields_required = 2;
dim_class->name = "Blur: Temporal";
dim_class->nick = "linearblend";
dim_class->latency = 0;
dim_class->latency = 1;
dism_class->interpolate_scanline_yuy2 =
deinterlace_scanline_linear_blend_packed_c;

View file

@ -77,10 +77,10 @@ gst_deinterlace_method_scaler_bob_class_init (GstDeinterlaceMethodScalerBobClass
GstDeinterlaceSimpleMethodClass *dism_class =
(GstDeinterlaceSimpleMethodClass *) klass;
dim_class->fields_required = 1;
dim_class->fields_required = 2;
dim_class->name = "Double lines";
dim_class->nick = "scalerbob";
dim_class->latency = 0;
dim_class->latency = 1;
dism_class->interpolate_scanline_ayuv =
deinterlace_scanline_scaler_bob_packed;

View file

@ -61,7 +61,9 @@
#define SEFUNC(x) Search_Effort_C_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
#endif
static void FUNCT_NAME(GstDeinterlaceMethod *d_method, const GstDeinterlaceField* history, guint history_count, GstBuffer *outbuf)
static void FUNCT_NAME(GstDeinterlaceMethod *d_method,
const GstDeinterlaceField* history, guint history_count,
GstBuffer *outbuf, int cur_field_idx)
{
GstDeinterlaceMethodTomsMoComp *self = GST_DEINTERLACE_METHOD_TOMSMOCOMP (d_method);
glong SearchEffort = self->search_effort;
@ -78,6 +80,21 @@ static void FUNCT_NAME(GstDeinterlaceMethod *d_method, const GstDeinterlaceField
gint rowsize;
gint FldHeight;
if (cur_field_idx + 2 > history_count || cur_field_idx < 1) {
GstDeinterlaceMethod *backup_method;
backup_method = g_object_new (gst_deinterlace_method_linear_get_type(),
NULL);
gst_deinterlace_method_setup (backup_method, d_method->format,
d_method->frame_width, d_method->frame_height);
gst_deinterlace_method_deinterlace_frame (backup_method,
history, history_count, outbuf, cur_field_idx);
g_object_unref (backup_method);
return;
}
/* double stride do address just every odd/even scanline */
src_pitch = self->parent.row_stride[0]*2;
dst_pitch = self->parent.row_stride[0];

View file

@ -68,7 +68,11 @@ static inline void
deinterlace_c (guint8 * dst, const guint8 * lum_m4, const guint8 * lum_m3,
const guint8 * lum_m2, const guint8 * lum_m1, const guint8 * lum, gint size)
{
deinterlace_line_vfir (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
if (lum_m2 == NULL) {
deinterlace_line_linear (dst, lum_m1, lum_m3, size);
} else {
deinterlace_line_vfir (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
}
}
static void
@ -127,6 +131,8 @@ deinterlace_line_planar_v_c (GstDeinterlaceSimpleMethod * self, guint8 * dst,
deinterlace_c (dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size);
}
#undef BUILD_X86_ASM
#ifdef BUILD_X86_ASM
#include "mmx.h"
static void
@ -251,7 +257,7 @@ gst_deinterlace_method_vfir_class_init (GstDeinterlaceMethodVFIRClass * klass)
dim_class->fields_required = 2;
dim_class->name = "Blur Vertical";
dim_class->nick = "vfir";
dim_class->latency = 0;
dim_class->latency = 1;
#ifdef BUILD_X86_ASM
if (cpu_flags & ORC_TARGET_MMX_MMX) {

View file

@ -48,28 +48,44 @@ static void
deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
}
}
static void
deinterlace_scanline_weave_planar_y (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
}
}
static void
deinterlace_scanline_weave_planar_u (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[1]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[1]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[1]);
}
}
static void
deinterlace_scanline_weave_planar_v (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[2]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[2]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[2]);
}
}
static void
@ -113,7 +129,7 @@ gst_deinterlace_method_weave_class_init (GstDeinterlaceMethodWeaveClass * klass)
dim_class->fields_required = 2;
dim_class->name = "Weave";
dim_class->nick = "weave";
dim_class->latency = 0;
dim_class->latency = 1;
dism_class->interpolate_scanline_ayuv = deinterlace_scanline_weave_packed;
dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;

View file

@ -48,76 +48,72 @@ static void
deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->b0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
}
}
static void
deinterlace_scanline_weave_planar_y (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->b0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
}
}
static void
deinterlace_scanline_weave_planar_u (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[1]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->b0, self->parent.row_stride[1]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[1]);
}
}
static void
deinterlace_scanline_weave_planar_v (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[2]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->b0, self->parent.row_stride[2]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[2]);
}
}
static void
copy_scanline_packed (GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb2, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->bb0, self->parent.row_stride[0]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[0]);
}
static void
copy_scanline_planar_y (GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb2, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->bb0, self->parent.row_stride[0]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[0]);
}
static void
copy_scanline_planar_u (GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb2, self->parent.row_stride[1]);
} else {
memcpy (out, scanlines->bb0, self->parent.row_stride[1]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[1]);
}
static void
copy_scanline_planar_v (GstDeinterlaceSimpleMethod * self, guint8 * out,
const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb2, self->parent.row_stride[2]);
} else {
memcpy (out, scanlines->bb0, self->parent.row_stride[2]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[2]);
}
G_DEFINE_TYPE (GstDeinterlaceMethodWeaveBFF, gst_deinterlace_method_weave_bff,
@ -131,10 +127,10 @@ gst_deinterlace_method_weave_bff_class_init (GstDeinterlaceMethodWeaveBFFClass *
GstDeinterlaceSimpleMethodClass *dism_class =
(GstDeinterlaceSimpleMethodClass *) klass;
dim_class->fields_required = 3;
dim_class->fields_required = 2;
dim_class->name = "Progressive: Bottom Field First";
dim_class->nick = "weavebff";
dim_class->latency = 0;
dim_class->latency = 1;
dism_class->interpolate_scanline_ayuv = deinterlace_scanline_weave_packed;
dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;

View file

@ -49,76 +49,72 @@ static void
deinterlace_scanline_weave_packed (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
}
}
static void
deinterlace_scanline_weave_planar_y (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[0]);
}
}
static void
deinterlace_scanline_weave_planar_u (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[1]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[1]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[1]);
}
}
static void
deinterlace_scanline_weave_planar_v (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
memcpy (out, scanlines->m1, self->parent.row_stride[2]);
if (scanlines->m1 == NULL) {
memcpy (out, scanlines->t0, self->parent.row_stride[2]);
} else {
memcpy (out, scanlines->m1, self->parent.row_stride[2]);
}
}
static void
copy_scanline_packed (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->bb2, self->parent.row_stride[0]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[0]);
}
static void
copy_scanline_planar_y (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb0, self->parent.row_stride[0]);
} else {
memcpy (out, scanlines->bb2, self->parent.row_stride[0]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[0]);
}
static void
copy_scanline_planar_u (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb0, self->parent.row_stride[1]);
} else {
memcpy (out, scanlines->bb2, self->parent.row_stride[1]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[1]);
}
static void
copy_scanline_planar_v (GstDeinterlaceSimpleMethod * self,
guint8 * out, const GstDeinterlaceScanlineData * scanlines)
{
/* FIXME: original code used m2 and m0 but this looks really bad */
if (scanlines->bottom_field) {
memcpy (out, scanlines->bb0, self->parent.row_stride[2]);
} else {
memcpy (out, scanlines->bb2, self->parent.row_stride[2]);
}
memcpy (out, scanlines->m0, self->parent.row_stride[2]);
}
G_DEFINE_TYPE (GstDeinterlaceMethodWeaveTFF, gst_deinterlace_method_weave_tff,
@ -132,10 +128,10 @@ gst_deinterlace_method_weave_tff_class_init (GstDeinterlaceMethodWeaveTFFClass *
GstDeinterlaceSimpleMethodClass *dism_class =
(GstDeinterlaceSimpleMethodClass *) klass;
dim_class->fields_required = 3;
dim_class->fields_required = 2;
dim_class->name = "Progressive: Top Field First";
dim_class->nick = "weavetff";
dim_class->latency = 0;
dim_class->latency = 1;
dism_class->interpolate_scanline_ayuv = deinterlace_scanline_weave_packed;
dism_class->interpolate_scanline_yuy2 = deinterlace_scanline_weave_packed;